Compare commits

..

62 Commits

Author SHA1 Message Date
040e148a73 release: 0.13.1-stable 2020-12-16 11:26:15 +01:00
b85d550ee0 build(deps-dev): bump pytest from 6.2.0 to 6.2.1 (#405)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.0 to 6.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.2.0...6.2.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-16 09:15:14 +01:00
ce95139d66 build(deps): bump boto3 from 1.16.36 to 1.16.37 (#404)
Bumps [boto3](https://github.com/boto/boto3) from 1.16.36 to 1.16.37.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.16.36...1.16.37)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-16 09:14:58 +01:00
46436a5780 build(deps): bump @types/chart.js from 2.9.28 to 2.9.29 in /web (#406)
Bumps [@types/chart.js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chart.js) from 2.9.28 to 2.9.29.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/chart.js)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-16 09:14:43 +01:00
835a9aaaf2 outposts: fix circular import 2020-12-16 00:00:36 +01:00
42005e7def outposts: ensure all Service Connection state updates are done by the task 2020-12-15 23:39:52 +01:00
d9956e1e9c outpost: fix invalid incluster config causing Outpost Service Connection list to fail 2020-12-15 21:17:33 +01:00
4b1e73251a root: fix messages showing for all sessions of a user 2020-12-15 15:19:15 +01:00
736dbdca33 build(deps-dev): bump @rollup/plugin-typescript in /web (#401)
Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins) from 8.0.0 to 8.1.0.
- [Release notes](https://github.com/rollup/plugins/releases)
- [Commits](https://github.com/rollup/plugins/compare/eslint-v8.0.0...typescript-v8.1.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 10:54:31 +01:00
789b8e5d3e build(deps-dev): bump @typescript-eslint/eslint-plugin in /web (#402)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.9.1 to 4.10.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.10.0/packages/eslint-plugin)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 10:28:11 +01:00
074b55f66b build(deps): bump boto3 from 1.16.35 to 1.16.36 (#398)
Bumps [boto3](https://github.com/boto/boto3) from 1.16.35 to 1.16.36.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.16.35...1.16.36)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 08:59:52 +01:00
d9bc5ea4d1 build(deps): bump rollup from 2.34.2 to 2.35.1 in /web (#399)
Bumps [rollup](https://github.com/rollup/rollup) from 2.34.2 to 2.35.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v2.34.2...v2.35.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 08:59:42 +01:00
716bb9f188 build(deps): bump @patternfly/patternfly from 4.65.6 to 4.70.2 in /web (#400)
Bumps [@patternfly/patternfly](https://github.com/patternfly/patternfly) from 4.65.6 to 4.70.2.
- [Release notes](https://github.com/patternfly/patternfly/releases)
- [Changelog](https://github.com/patternfly/patternfly/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/patternfly/patternfly/compare/prerelease-v4.65.6...prerelease-v4.70.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 08:59:30 +01:00
dd496619a2 build(deps-dev): bump @typescript-eslint/parser in /web (#403)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.9.1 to 4.10.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.10.0/packages/parser)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 08:59:04 +01:00
51d07f7913 proxy: output JSON logs 2020-12-14 19:41:32 +01:00
5c4163579b root: fix application icons now showing with docker-compose 2020-12-14 19:32:48 +01:00
5a73413d58 web: fix brand not showing on firefox 2020-12-14 19:26:02 +01:00
51a5d4bf49 docs: fix issues when overscrolling 2020-12-14 14:16:00 +01:00
8bbb854073 root: make docker-compose database name and username configurable 2020-12-14 12:27:33 +01:00
9f2e9e8444 release: 0.13.0-stable 2020-12-14 11:20:47 +01:00
a3d361f500 outposts: fix controller not using token.key 2020-12-14 11:03:49 +01:00
e9bb583b32 providers/proxy: ensure pb_proxy is deleted and ak_proxy is created 2020-12-14 10:47:49 +01:00
efccf47c83 build(deps): bump packaging from 20.7 to 20.8 (#388)
Bumps [packaging](https://github.com/pypa/packaging) from 20.7 to 20.8.
- [Release notes](https://github.com/pypa/packaging/releases)
- [Changelog](https://github.com/pypa/packaging/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pypa/packaging/compare/20.7...20.8)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 10:07:23 +01:00
a5b144cf8f build(deps): bump boto3 from 1.16.34 to 1.16.35 (#391)
Bumps [boto3](https://github.com/boto/boto3) from 1.16.34 to 1.16.35.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.16.34...1.16.35)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 10:07:12 +01:00
afc5a17fc2 build(deps): bump github.com/recws-org/recws in /proxy (#394)
Bumps [github.com/recws-org/recws](https://github.com/recws-org/recws) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/recws-org/recws/releases)
- [Commits](https://github.com/recws-org/recws/compare/v1.2.1...v1.2.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 10:06:59 +01:00
b3e0884b2e build(deps-dev): bump eslint-plugin-lit from 1.2.4 to 1.3.0 in /web (#396)
Bumps [eslint-plugin-lit](https://github.com/43081j/eslint-plugin-lit) from 1.2.4 to 1.3.0.
- [Release notes](https://github.com/43081j/eslint-plugin-lit/releases)
- [Commits](https://github.com/43081j/eslint-plugin-lit/compare/v1.2.4...v1.3.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 10:06:34 +01:00
078d648551 build(deps): bump uvicorn from 0.13.0 to 0.13.1 (#390)
* build(deps): bump uvicorn from 0.13.0 to 0.13.1

Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.13.0...0.13.1)

Signed-off-by: dependabot[bot] <support@github.com>

* root: remove asgi workaround when websocket is closed during connect

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens.langhammer@beryju.org>
2020-12-14 10:05:07 +01:00
41f9097592 build(deps-dev): bump pytest from 6.1.2 to 6.2.0 (#389)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.2 to 6.2.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.2...6.2.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 08:53:18 +01:00
562175741c build(deps): bump github.com/getsentry/sentry-go in /proxy (#392)
Bumps [github.com/getsentry/sentry-go](https://github.com/getsentry/sentry-go) from 0.7.0 to 0.9.0.
- [Release notes](https://github.com/getsentry/sentry-go/releases)
- [Changelog](https://github.com/getsentry/sentry-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-go/compare/v0.7.0...v0.9.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 08:52:56 +01:00
24e24cb97e build(deps-dev): bump typescript from 4.1.2 to 4.1.3 in /web (#395)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 08:52:40 +01:00
69b0a23a7d build(deps-dev): bump bandit from 1.6.3 to 1.7.0 (#387)
Bumps [bandit](https://github.com/PyCQA/bandit) from 1.6.3 to 1.7.0.
- [Release notes](https://github.com/PyCQA/bandit/releases)
- [Commits](https://github.com/PyCQA/bandit/compare/1.6.3...1.7.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 08:11:24 +01:00
f0f3245388 root: fix links to docs 2020-12-14 00:45:02 +01:00
99ca0d1f9f helm: fix missing /media/ route 2020-12-14 00:11:49 +01:00
c9f0d048a8 release: 0.13.0-rc4 2020-12-13 23:40:07 +01:00
90a94b5e3e root: fix paths for XML Schema files 2020-12-13 23:40:01 +01:00
ae1a8842db providers/oauth2: start adding tests for OAuthAuthorizationParams 2020-12-13 23:14:35 +01:00
a3b17d1ed4 admin: add tests for hidden form fields 2020-12-13 23:14:18 +01:00
41576e27be tests/integration: continue even if ssl can't be cleaned up 2020-12-13 21:51:59 +01:00
07082cb3aa tests/integration: add tests for Docker outpost using TLS connection 2020-12-13 21:30:33 +01:00
426cb33fab outposts: remove unused views 2020-12-13 21:25:05 +01:00
9e4f840d2d api: add token tests 2020-12-13 20:38:56 +01:00
e120d274e9 lib: fix sentry tests not running 2020-12-13 20:38:50 +01:00
977d3f6ef9 stages/user_write: add test that attributes without prefix are ignored 2020-12-13 20:38:43 +01:00
ecdbc917a5 admin: add api tests 2020-12-13 20:38:21 +01:00
0083cd55df sources/oauth: start adding tests for types 2020-12-13 20:03:34 +01:00
d380194e13 */saml: test against SAML Schema 2020-12-13 19:53:16 +01:00
32f5d5ba72 recovery: add test for invalid key 2020-12-13 18:46:36 +01:00
e818416863 policies/password: add invalid test case 2020-12-13 18:43:17 +01:00
7eed70cfe9 policies/hibp: add invalid test case 2020-12-13 18:42:59 +01:00
ea6ca23f57 lib: add tests for sentry integration 2020-12-13 18:41:47 +01:00
f056b026d6 lib: test edgecase for timedelta_from_string 2020-12-13 18:35:51 +01:00
1c0a6efeb1 flows/exporter: remove dead code since no stage is PolicyBindingModel 2020-12-13 18:25:30 +01:00
17732eea08 flows: add test for PLAN_CONTEXT_PENDING_USER_IDENTIFIER 2020-12-13 18:23:19 +01:00
aa5381fd59 flows: add tests case for reevaluate marker that keeps the stage 2020-12-13 18:07:11 +01:00
ffee86fcf3 crypto: simplify api/forms key validation 2020-12-13 18:06:52 +01:00
7ff7398aff admin: add tests for binding creation forms with invalid target 2020-12-13 18:06:34 +01:00
67925a39f2 web: fix source icons missing from static container 2020-12-13 17:50:30 +01:00
3b5e1c7b34 core: cleanup channels code, fix error when server side close 2020-12-13 17:46:34 +01:00
3e49acf7ae outposts: regularly ensure that all outposts have a valid service account and token 2020-12-13 17:10:56 +01:00
76764c4374 web: fix background for readonly inputs 2020-12-13 15:19:28 +01:00
9f6f8e1b55 outposts: update keys in outpost config 2020-12-13 15:15:20 +01:00
9590180c6c docs: update changelog 2020-12-13 12:41:42 +01:00
94 changed files with 2859 additions and 530 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.13.0-rc3
current_version = 0.13.1-stable
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)

View File

@ -18,11 +18,11 @@ jobs:
- name: Building Docker Image
run: docker build
--no-cache
-t beryju/authentik:0.13.0-rc3
-t beryju/authentik:0.13.1-stable
-t beryju/authentik:latest
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/authentik:0.13.0-rc3
run: docker push beryju/authentik:0.13.1-stable
- name: Push Docker Container to Registry (latest)
run: docker push beryju/authentik:latest
build-proxy:
@ -48,11 +48,11 @@ jobs:
cd proxy/
docker build \
--no-cache \
-t beryju/authentik-proxy:0.13.0-rc3 \
-t beryju/authentik-proxy:0.13.1-stable \
-t beryju/authentik-proxy:latest \
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/authentik-proxy:0.13.0-rc3
run: docker push beryju/authentik-proxy:0.13.1-stable
- name: Push Docker Container to Registry (latest)
run: docker push beryju/authentik-proxy:latest
build-static:
@ -69,11 +69,11 @@ jobs:
cd web/
docker build \
--no-cache \
-t beryju/authentik-static:0.13.0-rc3 \
-t beryju/authentik-static:0.13.1-stable \
-t beryju/authentik-static:latest \
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/authentik-static:0.13.0-rc3
run: docker push beryju/authentik-static:0.13.1-stable
- name: Push Docker Container to Registry (latest)
run: docker push beryju/authentik-static:latest
test-release:
@ -107,5 +107,5 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
tagName: 0.13.0-rc3
tagName: 0.13.1-stable
environment: beryjuorg-prod

View File

@ -38,6 +38,7 @@ RUN apt-get update && \
COPY ./authentik/ /authentik
COPY ./pytest.ini /
COPY ./xml /xml
COPY ./manage.py /
COPY ./lifecycle/ /lifecycle

View File

@ -1,5 +1,10 @@
all: lint-fix lint coverage gen
test-full:
coverage run manage.py test --failfast -v 3 .
coverage html
coverage report
test-integration:
k3d cluster create || exit 0
k3d kubeconfig write -o ~/.kube/config --overwrite

126
Pipfile.lock generated
View File

@ -53,10 +53,10 @@
},
"autobahn": {
"hashes": [
"sha256:24ce276d313e84d68241c3aef30d484f352b90a40168981b3640312c821df77b",
"sha256:86bbce30cdd407137c57670993a8f9bfdfe3f8e994b889181d85e844d5aa8dfb"
"sha256:491238c31f78721eaa9d0593909ab455a4ea68127aadd76ecf67185143f5f298",
"sha256:72b68a1ce1e10e3cbcc3b280aae86d5b2e7a1f409febab1ab91a8a3274113f6e"
],
"version": "==20.7.1"
"version": "==20.12.2"
},
"automat": {
"hashes": [
@ -74,18 +74,18 @@
},
"boto3": {
"hashes": [
"sha256:616cde1e326949020da85a5bacaa7ad287e9f117d10ac9c5bfb9150a98dfe1a7",
"sha256:ddad9ada00eccae1fc2da28c69531ba202fead562994ddcd9a9a232e993cd8a2"
"sha256:ad0e8dbd934d97b5228252785c0236c3ee4d464c14138f568e371bf43c6ea584",
"sha256:ee86c26b3d457aa4d0256d0535d13107c32aa33bb5eb2a0b2dac9d81c3aca405"
],
"index": "pypi",
"version": "==1.16.34"
"version": "==1.16.37"
},
"botocore": {
"hashes": [
"sha256:49f5e56a7382a65ee0873371edcd91bdba8fc3f70abe102ebc1a0da2e6fbed06",
"sha256:4d81d92127ef646ae0f0ee84c9c220c92fa82312e765c29f8cb3b000fdbdd038"
"sha256:5605c250f6f7c72ca50e45eab6186dfda03cb84296ca5b05f7416defcd3fcbc5",
"sha256:67bf1285455d79336ce7061da1768206b78f7a0efc13c8b4033fd348a74e7491"
],
"version": "==1.19.34"
"version": "==1.19.37"
},
"cachetools": {
"hashes": [
@ -396,10 +396,10 @@
},
"google-auth": {
"hashes": [
"sha256:5176db85f1e7e837a646cd9cede72c3c404ccf2e3373d9ee14b2db88febad440",
"sha256:b728625ff5dfce8f9e56a499c8a4eb51443a67f20f6d28b67d5774c310ec4b6b"
"sha256:0b0e026b412a0ad096e753907559e4bdb180d9ba9f68dd9036164db4fdc4ad2e",
"sha256:ce752cc51c31f479dbf9928435ef4b07514b20261b021c7383bee4bda646acb8"
],
"version": "==1.23.0"
"version": "==1.24.0"
},
"gunicorn": {
"hashes": [
@ -646,26 +646,46 @@
},
"msgpack": {
"hashes": [
"sha256:002a0d813e1f7b60da599bdf969e632074f9eec1b96cbed8fb0973a63160a408",
"sha256:25b3bc3190f3d9d965b818123b7752c5dfb953f0d774b454fd206c18fe384fb8",
"sha256:271b489499a43af001a2e42f42d876bb98ccaa7e20512ff37ca78c8e12e68f84",
"sha256:39c54fdebf5fa4dda733369012c59e7d085ebdfe35b6cf648f09d16708f1be5d",
"sha256:4233b7f86c1208190c78a525cd3828ca1623359ef48f78a6fea4b91bb995775a",
"sha256:5bea44181fc8e18eed1d0cd76e355073f00ce232ff9653a0ae88cb7d9e643322",
"sha256:5dba6d074fac9b24f29aaf1d2d032306c27f04187651511257e7831733293ec2",
"sha256:7a22c965588baeb07242cb561b63f309db27a07382825fc98aecaf0827c1538e",
"sha256:908944e3f038bca67fcfedb7845c4a257c7749bf9818632586b53bcf06ba4b97",
"sha256:9534d5cc480d4aff720233411a1f765be90885750b07df772380b34c10ecb5c0",
"sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be",
"sha256:b3758dfd3423e358bbb18a7cccd1c74228dffa7a697e5be6cb9535de625c0dbf",
"sha256:c901e8058dd6653307906c5f157f26ed09eb94a850dddd989621098d347926ab",
"sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08",
"sha256:db685187a415f51d6b937257474ca72199f393dad89534ebbdd7d7a3b000080e",
"sha256:e35b051077fc2f3ce12e7c6a34cf309680c63a842db3a0616ea6ed25ad20d272",
"sha256:e7bbdd8e2b277b77782f3ce34734b0dfde6cbe94ddb74de8d733d603c7f9e2b1",
"sha256:ea41c9219c597f1d2bf6b374d951d310d58684b5de9dc4bd2976db9e1e22c140"
"sha256:01835e300967e5ad6fdbfc36eafe74df67ff47e16e0d6dee8766630550315903",
"sha256:03c5554315317d76c25a15569dd52ac6047b105df71e861f24faf9675672b72d",
"sha256:0968b368a9a9081435bfcb7a57a1e8b75c7bf038ef911b369acd2e038c7f873a",
"sha256:1d7ab166401f7789bf11262439336c0a01b878f0d602e48f35c35d2e3a555820",
"sha256:1e8d27bac821f8aa909904a704a67e5e8bc2e42b153415fc3621b7afbc06702b",
"sha256:1fc9f21da9fd77088ebfd3c9941b044ca3f4a048e85f7ff5727f26bcdbffed61",
"sha256:20196229acc193939223118c7420838749d5b0cece49cd397739a3a6ffcfe2d1",
"sha256:2933443313289725f16bd7b99a8c3aa6a2cca1549e661d7407f056a0af80bf7b",
"sha256:2966b155356fd231fa441131d7301e1596ee38974ad56dc57fd752fdbe2bb63f",
"sha256:29a6fb3729215b6fcab786ef4f460a5406a5c056f7021191f70ff7712a3f6ba4",
"sha256:35cbefa7d7bddfb4b0770a1b9ff721cd8dfe9a680947a68457974d5e3e6acc2f",
"sha256:35ff1ac162a77fb78be360d9f771d36cbf1202e94fc6d70e284ad5db6ab72608",
"sha256:40dd1ac7420f071e96b3e4a4a7b8e69546a6f8065ff5995dbacf53f86207eb98",
"sha256:4bea1938e484c9caca9585105f447d6807c496c153b7244fa726b3cc4a68ec9e",
"sha256:4e58b9f4a99bc3a90859bb006ec4422448a5ce39e5cd6e7498c56de5dcec9c34",
"sha256:66d47e952856bfcde46d8351380d0b5b928a73112b66bc06d5367dfcc077c06a",
"sha256:69f6aa503378548ea1e760c11aeb6fc91952bf3634fd806a38a0e47edb507fcd",
"sha256:7033215267a0e9f60f4a5e4fb2228a932c404f237817caff8dc3115d9e7cd975",
"sha256:7b50afd767cc053ad92fad39947c3670db27305fd1c49acded44d9d9ac8b56fd",
"sha256:99ea9e65876546743b2b8bb5bc7adefbb03b9da78a899827467da197a48f790b",
"sha256:abcc62303ac4d789878d4aac4cdba1bbe2adb478d67be99cd4a6d56ac3a4028f",
"sha256:b107f9b36665bf7d7c6176a938a361a7aba16aa179d833919448f77287866484",
"sha256:b5b27923b6c98a2616b7e906a29e4e10e1b4424aea87a0e0d5636327dc6ea315",
"sha256:bf8eedc7bfbf63cbc9abe58287c32d78780a347835e82c23033c68f11f80bb05",
"sha256:c144ff4954a6ea40aa603600c8be175349588fc68696092889fa34ab6e055060",
"sha256:c4e5f96a1d0d916ce7a16decb7499e8923ddef007cf7d68412fb68767766648a",
"sha256:c60e8b2bf754b8dcc1075c5bee0b177ed9193e7cbd2377faaf507120a948e697",
"sha256:c82fc6cdba5737eb6ed0c926a30a5d56e7b050297375a16d6c5ad89b576fd979",
"sha256:ce4ebe2c79411cd5671b20862831880e7850a2de699cff6626f48853fde61ae6",
"sha256:d113c6b1239c62669ef3063693842605a3edbfebc39a333cf91ba60d314afe6d",
"sha256:d3cea07ad16919a44e8d1ea67efa5244855cdce807d672f41694acc24d08834e",
"sha256:d76672602db16e3f44bc1a85c7ee5f15d79e02fcf5bc9d133c2954753be6eddc",
"sha256:decf2091b75987ca2564e3b742f9614eb7d57e39ff04eaa68af7a3fc5648f7ed",
"sha256:e13b9007af66a3f62574bc0a13843df0e4402f5ee4b00a02aa1803f01d26b9fb",
"sha256:e157edf4213dacafb0f862e0b7a3a18448250cec91aa1334f432f49028acc650",
"sha256:e234ff83628ca3ab345bf97fb36ccbf6d2f1700f5e08868643bf4489edc960f8",
"sha256:f08d9dd3ce0c5e972dc4653f0fb66d2703941e65356388c13032b578dd718261",
"sha256:f20d7d4f1f0728560408ba6933154abccf0c20f24642a2404b43d5c23e4119ab"
],
"version": "==1.0.0"
"version": "==1.0.1"
},
"oauthlib": {
"hashes": [
@ -676,11 +696,11 @@
},
"packaging": {
"hashes": [
"sha256:05af3bb85d320377db281cf254ab050e1a7ebcbf5410685a9a407e18a1f81236",
"sha256:eb41423378682dadb7166144a4926e443093863024de508ca5c9737d6bc08376"
"sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858",
"sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"
],
"index": "pypi",
"version": "==20.7"
"version": "==20.8"
},
"prometheus-client": {
"hashes": [
@ -855,10 +875,10 @@
},
"pyopenssl": {
"hashes": [
"sha256:898aefbde331ba718570244c3b01dcddb1b31a3b336613436a45e52e27d9a82d",
"sha256:92f08eccbd73701cf744e8ffd6989aa7842d48cbe3fea8a7c031c5647f590ac5"
"sha256:4c231c759543ba02560fcd2480c48dcec4dae34c9da7d3747c508227e0624b51",
"sha256:818ae18e06922c066f777a33f1fca45786d85edfe71cd043de6379337a7f274b"
],
"version": "==20.0.0"
"version": "==20.0.1"
},
"pyparsing": {
"hashes": [
@ -948,7 +968,7 @@
"sha256:109ea5a66744dd859bf16fe904b8d8b627adafb9408753161e766a92e7d681fa",
"sha256:6166864e23d6b5195a5cfed6cd9fed0fe774e226d8f854fcb23b7bbef0350233"
],
"markers": "python_version >= '3.5'",
"markers": "python_version >= '3.6'",
"version": "==4.6"
},
"ruamel.yaml": {
@ -1073,11 +1093,11 @@
"standard"
],
"hashes": [
"sha256:28420526640d800aabe648038f8e2ea8ba2a8bdc363002eecd5dfc57a0f75ab7",
"sha256:5123606e0f1d15ffbe0f63161c5078f7c28f350c5eb102435671eae58046db0f"
"sha256:2a7b17f4d9848d6557ccc2274a5f7c97f1daf037d130a0c6918f67cd9bc8cdf5",
"sha256:6fcce74c00b77d4f4b3ed7ba1b2a370d27133bfdb46f835b7a76dfe0a8c110ae"
],
"index": "pypi",
"version": "==0.13.0"
"version": "==0.13.1"
},
"uvloop": {
"hashes": [
@ -1263,11 +1283,11 @@
},
"bandit": {
"hashes": [
"sha256:2ff3fe35fe3212c0be5fc9c4899bd0108e2b5239c5ff62fb174639e4660fe958",
"sha256:d02dfe250f4aa2d166c127ad81d192579e2bfcdb8501717c0e2005e35a6bcf60"
"sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07",
"sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"
],
"index": "pypi",
"version": "==1.6.3"
"version": "==1.7.0"
},
"black": {
"hashes": [
@ -1453,11 +1473,11 @@
},
"packaging": {
"hashes": [
"sha256:05af3bb85d320377db281cf254ab050e1a7ebcbf5410685a9a407e18a1f81236",
"sha256:eb41423378682dadb7166144a4926e443093863024de508ca5c9737d6bc08376"
"sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858",
"sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"
],
"index": "pypi",
"version": "==20.7"
"version": "==20.8"
},
"pathspec": {
"hashes": [
@ -1496,10 +1516,10 @@
},
"py": {
"hashes": [
"sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2",
"sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
],
"version": "==1.9.0"
"version": "==1.10.0"
},
"pycodestyle": {
"hashes": [
@ -1566,11 +1586,11 @@
},
"pytest": {
"hashes": [
"sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe",
"sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e"
"sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8",
"sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"
],
"index": "pypi",
"version": "==6.1.2"
"version": "==6.2.1"
},
"pytest-django": {
"hashes": [

View File

@ -6,9 +6,9 @@ As authentik is currently in a pre-stable, only the latest "stable" version is s
| Version | Supported |
| -------- | ------------------ |
| 0.10.x | :white_check_mark: |
| 0.11.x | :white_check_mark: |
| 0.12.x | :white_check_mark: |
| 0.13.x | :white_check_mark: |
## Reporting a Vulnerability

View File

@ -1,2 +1,2 @@
"""authentik"""
__version__ = "0.13.0-rc3"
__version__ = "0.13.1-stable"

View File

@ -0,0 +1,37 @@
"""test admin api"""
from json import loads
from django.shortcuts import reverse
from django.test import TestCase
from authentik import __version__
from authentik.core.models import Group, User
class TestAdminAPI(TestCase):
"""test admin api"""
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create(username="test-user")
self.group = Group.objects.create(name="superusers", is_superuser=True)
self.group.users.add(self.user)
self.group.save()
self.client.force_login(self.user)
def test_overview(self):
"""Test Overview API"""
response = self.client.get(reverse("authentik_api:admin_overview-list"))
self.assertEqual(response.status_code, 200)
body = loads(response.content)
self.assertEqual(body["version"], __version__)
def test_metrics(self):
"""Test metrics API"""
response = self.client.get(reverse("authentik_api:admin_metrics-list"))
self.assertEqual(response.status_code, 200)
def test_tasks(self):
"""Test tasks metrics API"""
response = self.client.get(reverse("authentik_api:admin_system_tasks-list"))
self.assertEqual(response.status_code, 200)

View File

@ -1,9 +1,13 @@
"""admin tests"""
from uuid import uuid4
from django import forms
from django.test import TestCase
from django.test.client import RequestFactory
from authentik.admin.views.policies_bindings import PolicyBindingCreateView
from authentik.core.models import Application
from authentik.policies.forms import PolicyBindingForm
class TestPolicyBindingView(TestCase):
@ -18,9 +22,22 @@ class TestPolicyBindingView(TestCase):
view = PolicyBindingCreateView(request=request)
self.assertEqual(view.get_initial(), {})
def test_with_param(self):
def test_with_params_invalid(self):
"""Test PolicyBindingCreateView with invalid get params"""
request = self.factory.get("/", {"target": uuid4()})
view = PolicyBindingCreateView(request=request)
self.assertEqual(view.get_initial(), {})
def test_with_params(self):
"""Test PolicyBindingCreateView with get params"""
target = Application.objects.create(name="test")
request = self.factory.get("/", {"target": target.pk.hex})
view = PolicyBindingCreateView(request=request)
self.assertEqual(view.get_initial(), {"target": target, "order": 0})
self.assertTrue(
isinstance(
PolicyBindingForm(initial={"target": "foo"}).fields["target"].widget,
forms.HiddenInput,
)
)

View File

@ -1,8 +1,12 @@
"""admin tests"""
from uuid import uuid4
from django import forms
from django.test import TestCase
from django.test.client import RequestFactory
from authentik.admin.views.stages_bindings import StageBindingCreateView
from authentik.flows.forms import FlowStageBindingForm
from authentik.flows.models import Flow
@ -18,9 +22,22 @@ class TestStageBindingView(TestCase):
view = StageBindingCreateView(request=request)
self.assertEqual(view.get_initial(), {})
def test_with_param(self):
def test_with_params_invalid(self):
"""Test StageBindingCreateView with invalid get params"""
request = self.factory.get("/", {"target": uuid4()})
view = StageBindingCreateView(request=request)
self.assertEqual(view.get_initial(), {})
def test_with_params(self):
"""Test StageBindingCreateView with get params"""
target = Flow.objects.create(name="test", slug="test")
request = self.factory.get("/", {"target": target.pk.hex})
view = StageBindingCreateView(request=request)
self.assertEqual(view.get_initial(), {"target": target, "order": 0})
self.assertTrue(
isinstance(
FlowStageBindingForm(initial={"target": "foo"}).fields["target"].widget,
forms.HiddenInput,
)
)

View File

@ -1,5 +1,6 @@
"""API Authentication"""
from base64 import b64decode
from binascii import Error
from typing import Any, Optional, Tuple, Union
from rest_framework.authentication import BaseAuthentication, get_authorization_header
@ -24,7 +25,7 @@ def token_from_header(raw_header: bytes) -> Optional[Token]:
return None
try:
auth_credentials = b64decode(auth_credentials.encode()).decode()
except UnicodeDecodeError:
except (UnicodeDecodeError, Error):
return None
# Accept credentials with username and without
if ":" in auth_credentials:

37
authentik/api/tests.py Normal file
View File

@ -0,0 +1,37 @@
"""Test API Authentication"""
from base64 import b64encode
from django.test import TestCase
from guardian.shortcuts import get_anonymous_user
from authentik.api.auth import token_from_header
from authentik.core.models import Token, TokenIntents
class TestAPIAuth(TestCase):
"""Test API Authentication"""
def test_valid(self):
"""Test valid token"""
token = Token.objects.create(
intent=TokenIntents.INTENT_API, user=get_anonymous_user()
)
auth = b64encode(f":{token.key}".encode()).decode()
self.assertEqual(token_from_header(f"Basic {auth}".encode()), token)
def test_invalid_type(self):
"""Test invalid type"""
self.assertIsNone(token_from_header("foo bar".encode()))
def test_invalid_decode(self):
"""Test invalid bas64"""
self.assertIsNone(token_from_header("Basic bar".encode()))
def test_invalid_empty_password(self):
"""Test invalid with empty password"""
self.assertIsNone(token_from_header("Basic :".encode()))
def test_invalid_no_token(self):
"""Test invalid with no token"""
auth = b64encode(":abc".encode()).decode()
self.assertIsNone(token_from_header(f"Basic :{auth}".encode()))

View File

@ -1,4 +1,5 @@
"""Channels base classes"""
from channels.exceptions import DenyConnection
from channels.generic.websocket import JsonWebsocketConsumer
from structlog import get_logger
@ -17,16 +18,13 @@ class AuthJsonConsumer(JsonWebsocketConsumer):
headers = dict(self.scope["headers"])
if b"authorization" not in headers:
LOGGER.warning("WS Request without authorization header")
self.close()
return False
raise DenyConnection()
raw_header = headers[b"authorization"]
token = token_from_header(raw_header)
if not token:
LOGGER.warning("Failed to authenticate")
self.close()
return False
raise DenyConnection()
self.user = token.user
return True

View File

@ -22,16 +22,15 @@ class CertificateKeyPairSerializer(ModelSerializer):
def validate_key_data(self, value):
"""Verify that input is a valid PEM RSA Key"""
# Since this field is optional, data can be empty.
if value == "":
return value
try:
load_pem_private_key(
str.encode("\n".join([x.strip() for x in value.split("\n")])),
password=None,
backend=default_backend(),
)
except ValueError:
raise ValidationError("Unable to load private key.")
if value != "":
try:
load_pem_private_key(
str.encode("\n".join([x.strip() for x in value.split("\n")])),
password=None,
backend=default_backend(),
)
except ValueError:
raise ValidationError("Unable to load private key.")
return value
class Meta:

View File

@ -26,16 +26,15 @@ class CertificateKeyPairForm(forms.ModelForm):
"""Verify that input is a valid PEM RSA Key"""
key_data = self.cleaned_data["key_data"]
# Since this field is optional, data can be empty.
if key_data == "":
return key_data
try:
load_pem_private_key(
str.encode("\n".join([x.strip() for x in key_data.split("\n")])),
password=None,
backend=default_backend(),
)
except ValueError:
raise forms.ValidationError("Unable to load private key.")
if key_data != "":
try:
load_pem_private_key(
str.encode("\n".join([x.strip() for x in key_data.split("\n")])),
password=None,
backend=default_backend(),
)
except ValueError:
raise forms.ValidationError("Unable to load private key.")
return key_data
class Meta:

View File

@ -3,14 +3,17 @@ from unittest.mock import MagicMock, PropertyMock, patch
from django.http import HttpRequest, HttpResponse
from django.shortcuts import reverse
from django.test import Client, TestCase
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils.encoding import force_str
from authentik.core.models import User
from authentik.flows.exceptions import EmptyFlowException, FlowNonApplicableException
from authentik.flows.markers import ReevaluateMarker, StageMarker
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
from authentik.flows.planner import FlowPlan
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_PLAN
from authentik.flows.planner import FlowPlan, FlowPlanner
from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, StageView
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_PLAN, FlowExecutorView
from authentik.lib.config import CONFIG
from authentik.policies.dummy.models import DummyPolicy
from authentik.policies.http import AccessDeniedResponse
@ -35,7 +38,7 @@ class TestFlowExecutor(TestCase):
"""Test views logic"""
def setUp(self):
self.client = Client()
self.request_factory = RequestFactory()
def test_existing_plan_diff_flow(self):
"""Check that a plan for a different flow cancels the current plan"""
@ -276,6 +279,83 @@ class TestFlowExecutor(TestCase):
{"type": "redirect", "to": reverse("authentik_core:shell")},
)
def test_reevaluate_keep(self):
"""Test planner with re-evaluate (everything is kept)"""
flow = Flow.objects.create(
name="test-default-context",
slug="test-default-context",
designation=FlowDesignation.AUTHENTICATION,
)
true_policy = DummyPolicy.objects.create(result=True, wait_min=1, wait_max=2)
binding = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy1"), order=0
)
binding2 = FlowStageBinding.objects.create(
target=flow,
stage=DummyStage.objects.create(name="dummy2"),
order=1,
re_evaluate_policies=True,
)
binding3 = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy3"), order=2
)
PolicyBinding.objects.create(policy=true_policy, target=binding2, order=0)
# Here we patch the dummy policy to evaluate to true so the stage is included
with patch(
"authentik.policies.dummy.models.DummyPolicy.passes", POLICY_RETURN_TRUE
):
exec_url = reverse(
"authentik_flows:flow-executor", kwargs={"flow_slug": flow.slug}
)
# First request, run the planner
response = self.client.get(exec_url)
self.assertEqual(response.status_code, 200)
plan: FlowPlan = self.client.session[SESSION_KEY_PLAN]
self.assertEqual(plan.stages[0], binding.stage)
self.assertEqual(plan.stages[1], binding2.stage)
self.assertEqual(plan.stages[2], binding3.stage)
self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], ReevaluateMarker)
self.assertIsInstance(plan.markers[2], StageMarker)
# Second request, this passes the first dummy stage
response = self.client.post(exec_url)
self.assertEqual(response.status_code, 302)
plan: FlowPlan = self.client.session[SESSION_KEY_PLAN]
self.assertEqual(plan.stages[0], binding2.stage)
self.assertEqual(plan.stages[1], binding3.stage)
self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], StageMarker)
# Third request, this passes the first dummy stage
response = self.client.post(exec_url)
self.assertEqual(response.status_code, 302)
plan: FlowPlan = self.client.session[SESSION_KEY_PLAN]
self.assertEqual(plan.stages[0], binding3.stage)
self.assertIsInstance(plan.markers[0], StageMarker)
# third request, this should trigger the re-evaluate
# We do this request without the patch, so the policy results in false
response = self.client.post(exec_url)
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(
force_str(response.content),
{"type": "redirect", "to": reverse("authentik_core:shell")},
)
def test_reevaluate_remove_consecutive(self):
"""Test planner with re-evaluate (consecutive stages are removed)"""
flow = Flow.objects.create(
@ -351,3 +431,33 @@ class TestFlowExecutor(TestCase):
force_str(response.content),
{"type": "redirect", "to": reverse("authentik_core:shell")},
)
def test_stageview_user_identifier(self):
"""Test PLAN_CONTEXT_PENDING_USER_IDENTIFIER"""
flow = Flow.objects.create(
name="test-default-context",
slug="test-default-context",
designation=FlowDesignation.AUTHENTICATION,
)
FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy"), order=0
)
ident = "test-identifier"
user = User.objects.create(username="test-user")
request = self.request_factory.get(
reverse("authentik_flows:flow-executor", kwargs={"flow_slug": flow.slug}),
)
request.user = user
planner = FlowPlanner(flow)
plan = planner.plan(
request, default_context={PLAN_CONTEXT_PENDING_USER_IDENTIFIER: ident}
)
executor = FlowExecutorView()
executor.plan = plan
executor.flow = flow
stage_view = StageView(executor)
self.assertEqual(ident, stage_view.get_context_data()["user"].username)

View File

@ -61,7 +61,7 @@ class DataclassEncoder(JSONEncoder):
return asdict(o)
if isinstance(o, UUID):
return str(o)
return super().default(o)
return super().default(o) # pragma: no cover
class EntryInvalidError(SentryIgnoredException):

View File

@ -11,7 +11,7 @@ from authentik.flows.transfer.common import (
FlowBundle,
FlowBundleEntry,
)
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel
from authentik.policies.models import Policy, PolicyBinding
from authentik.stages.prompt.models import PromptStage
@ -31,11 +31,6 @@ class FlowExporter:
def _prepare_pbm(self):
self.pbm_uuids = [self.flow.pbm_uuid]
for stage_subclass in Stage.__subclasses__():
if issubclass(stage_subclass, PolicyBindingModel):
self.pbm_uuids += stage_subclass.objects.filter(
flow=self.flow
).values_list("pbm_uuid", flat=True)
self.pbm_uuids += FlowStageBinding.objects.filter(target=self.flow).values_list(
"pbm_uuid", flat=True
)

View File

@ -1,55 +0,0 @@
"""authentik lib navbar Templatetag"""
from django import template
from django.http import HttpRequest
from structlog import get_logger
register = template.Library()
LOGGER = get_logger()
ACTIVE_STRING = "pf-m-current"
@register.simple_tag(takes_context=True)
def is_active(context, *args: str, **_) -> str:
"""Return whether a navbar link is active or not."""
request: HttpRequest = context.get("request")
if not request.resolver_match:
return ""
match = request.resolver_match
for url in args:
if ":" in url:
app_name, url = url.split(":")
if match.app_name == app_name and match.url_name == url:
return ACTIVE_STRING
else:
if match.url_name == url:
return ACTIVE_STRING
return ""
@register.simple_tag(takes_context=True)
def is_active_url(context, view: str) -> str:
"""Return whether a navbar link is active or not."""
request: HttpRequest = context.get("request")
if not request.resolver_match:
return ""
match = request.resolver_match
current_full_url = f"{match.app_name}:{match.url_name}"
if current_full_url == view:
return ACTIVE_STRING
return ""
@register.simple_tag(takes_context=True)
def is_active_app(context, *args: str) -> str:
"""Return True if current link is from app"""
request: HttpRequest = context.get("request")
if not request.resolver_match:
return ""
for app_name in args:
if request.resolver_match.app_name == app_name:
return ACTIVE_STRING
return ""

View File

View File

@ -0,0 +1,18 @@
"""test sentry integration"""
from django.test import TestCase
from authentik.lib.sentry import SentryIgnoredException, before_send
class TestSentry(TestCase):
"""test sentry integration"""
def test_error_not_sent(self):
"""Test SentryIgnoredError not sent"""
self.assertIsNone(
before_send(None, {"exc_info": (0, SentryIgnoredException(), 0)})
)
def test_error_sent(self):
"""Test error sent"""
self.assertIsNone(before_send(None, {"exc_info": (0, ValueError(), 0)}))

View File

@ -20,6 +20,8 @@ class TestTimeUtils(TestCase):
"""Test invalid expression"""
with self.assertRaises(ValueError):
timedelta_from_string("foo")
with self.assertRaises(ValueError):
timedelta_from_string("bar=baz")
def test_validation(self):
"""Test Django model field validator"""

View File

@ -35,4 +35,6 @@ def timedelta_from_string(expr: str) -> datetime.timedelta:
if key.lower() not in ALLOWED_KEYS:
continue
kwargs[key.lower()] = float(value)
if len(kwargs) < 1:
raise ValueError("No valid keys to pass to timedelta")
return datetime.timedelta(**kwargs)

View File

@ -22,7 +22,6 @@ class AuthentikOutpostConfig(AppConfig):
name = "authentik.outposts"
label = "authentik_outposts"
mountpoint = "outposts/"
verbose_name = "authentik Outpost"
def ready(self):

View File

@ -2,8 +2,9 @@
from dataclasses import asdict, dataclass, field
from datetime import datetime
from enum import IntEnum
from typing import Any, Dict
from typing import Any, Dict, Optional
from channels.exceptions import DenyConnection
from dacite import from_dict
from dacite.data import Data
from guardian.shortcuts import get_objects_for_user
@ -39,18 +40,16 @@ class WebsocketMessage:
class OutpostConsumer(AuthJsonConsumer):
"""Handler for Outposts that connect over websockets for health checks and live updates"""
outpost: Outpost
outpost: Optional[Outpost] = None
def connect(self):
if not super().connect():
return
super().connect()
uuid = self.scope["url_route"]["kwargs"]["pk"]
outpost = get_objects_for_user(
self.user, "authentik_outposts.view_outpost"
).filter(pk=uuid)
if not outpost.exists():
self.close()
return
raise DenyConnection()
self.accept()
self.outpost = outpost.first()
OutpostState(
@ -60,7 +59,8 @@ class OutpostConsumer(AuthJsonConsumer):
# pylint: disable=unused-argument
def disconnect(self, close_code):
OutpostState.for_channel(self.outpost, self.channel_name).delete()
if self.outpost:
OutpostState.for_channel(self.outpost, self.channel_name).delete()
LOGGER.debug("removed channel from cache", channel_name=self.channel_name)
def receive_json(self, content: Data):

View File

@ -46,7 +46,7 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]):
"authentik_host_insecure": b64string(
str(self.controller.outpost.config.authentik_host_insecure)
),
"token": b64string(self.controller.outpost.token.token_uuid.hex),
"token": b64string(self.controller.outpost.token.key),
},
)

View File

@ -0,0 +1,38 @@
# Generated by Django 3.1.4 on 2020-12-13 14:07
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def update_config_prefix(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
alias = schema_editor.connection.alias
Outpost = apps.get_model("authentik_outposts", "Outpost")
for outpost in Outpost.objects.using(alias).all():
config = outpost._config
for key in list(config):
if "passbook" in key:
new_key = key.replace("passbook", "authentik")
config[new_key] = config[key]
del config[key]
outpost._config = config
outpost.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_outposts", "0013_auto_20201203_2009"),
]
operations = [
migrations.RunPython(update_config_prefix),
migrations.AlterField(
model_name="dockerserviceconnection",
name="url",
field=models.TextField(
help_text="Can be in the format of 'unix://<path>' when connecting to a local docker daemon, or 'https://<hostname>:2376' when connecting to a remote system."
),
),
]

View File

@ -113,17 +113,24 @@ class OutpostServiceConnection(models.Model):
objects = InheritanceManager()
@property
def state_key(self) -> str:
"""Key used to save connection state in cache"""
return f"outpost_service_connection_{self.pk.hex}"
@property
def state(self) -> OutpostServiceConnectionState:
"""Get state of service connection"""
state_key = f"outpost_service_connection_{self.pk.hex}"
state = cache.get(state_key, None)
from authentik.outposts.tasks import outpost_service_connection_state
state = cache.get(self.state_key, None)
if not state:
state = self._get_state()
cache.set(state_key, state, timeout=0)
outpost_service_connection_state.delay(self.pk)
return OutpostServiceConnectionState("", False)
return state
def _get_state(self) -> OutpostServiceConnectionState:
def fetch_state(self) -> OutpostServiceConnectionState:
"""Fetch current Service Connection state"""
raise NotImplementedError
@property
@ -140,7 +147,14 @@ class OutpostServiceConnection(models.Model):
class DockerServiceConnection(OutpostServiceConnection):
"""Service Connection to a Docker endpoint"""
url = models.TextField()
url = models.TextField(
help_text=_(
(
"Can be in the format of 'unix://<path>' when connecting to a local docker daemon, "
"or 'https://<hostname>:2376' when connecting to a remote system."
)
)
)
tls_verification = models.ForeignKey(
CertificateKeyPair,
null=True,
@ -196,7 +210,7 @@ class DockerServiceConnection(OutpostServiceConnection):
raise ServiceConnectionInvalid from exc
return client
def _get_state(self) -> OutpostServiceConnectionState:
def fetch_state(self) -> OutpostServiceConnectionState:
try:
client = self.client()
return OutpostServiceConnectionState(
@ -232,7 +246,7 @@ class KubernetesServiceConnection(OutpostServiceConnection):
def __str__(self) -> str:
return f"Kubernetes Service-Connection {self.name}"
def _get_state(self) -> OutpostServiceConnectionState:
def fetch_state(self) -> OutpostServiceConnectionState:
try:
client = self.client()
api_instance = VersionApi(client)
@ -240,7 +254,7 @@ class KubernetesServiceConnection(OutpostServiceConnection):
return OutpostServiceConnectionState(
version=version.git_version, healthy=True
)
except (OpenApiException, HTTPError):
except (OpenApiException, HTTPError, ServiceConnectionInvalid):
return OutpostServiceConnectionState(version="", healthy=False)
def client(self) -> ApiClient:

View File

@ -12,4 +12,9 @@ CELERY_BEAT_SCHEDULE = {
"schedule": crontab(minute=0, hour="*"),
"options": {"queue": "authentik_scheduled"},
},
"outpost_token_ensurer": {
"task": "authentik.outposts.tasks.outpost_token_ensurer",
"schedule": crontab(minute="*/5"),
"options": {"queue": "authentik_scheduled"},
},
}

View File

@ -35,21 +35,23 @@ def outpost_controller_all():
@CELERY_APP.task()
def outpost_service_connection_state(state_pk: Any):
def outpost_service_connection_state(connection_pk: Any):
"""Update cached state of a service connection"""
connection: OutpostServiceConnection = (
OutpostServiceConnection.objects.filter(pk=state_pk).select_subclasses().first()
OutpostServiceConnection.objects.filter(pk=connection_pk)
.select_subclasses()
.first()
)
cache.delete(f"outpost_service_connection_{connection.pk.hex}")
_ = connection.state
state = connection.fetch_state()
cache.set(connection.state_key, state, timeout=0)
@CELERY_APP.task(bind=True, base=MonitoredTask)
def outpost_service_connection_monitor(self: MonitoredTask):
"""Regularly check the state of Outpost Service Connections"""
for connection in OutpostServiceConnection.objects.select_subclasses():
cache.delete(f"outpost_service_connection_{connection.pk.hex}")
_ = connection.state
for connection in OutpostServiceConnection.objects.all():
outpost_service_connection_state.delay(connection.pk)
self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL))
@ -90,6 +92,21 @@ def outpost_pre_delete(outpost_pk: str):
ProxyKubernetesController(outpost, service_connection).down()
@CELERY_APP.task(bind=True, base=MonitoredTask)
def outpost_token_ensurer(self: MonitoredTask):
"""Periodically ensure that all Outposts have valid Service Accounts
and Tokens"""
all_outposts = Outpost.objects.all()
for outpost in all_outposts:
_ = outpost.token
self.set_status(
TaskResult(
TaskResultStatus.SUCCESSFUL,
[f"Successfully checked {len(all_outposts)} Outposts."],
)
)
@CELERY_APP.task()
def outpost_post_save(model_class: str, model_pk: Any):
"""If an Outpost is saved, Ensure that token is created/updated

View File

@ -1,11 +0,0 @@
"""authentik outposts urls"""
from django.urls import path
from authentik.outposts.views import KubernetesManifestView, SetupView
urlpatterns = [
path(
"<uuid:outpost_pk>/k8s/", KubernetesManifestView.as_view(), name="k8s-manifest"
),
path("<uuid:outpost_pk>/", SetupView.as_view(), name="setup"),
]

View File

@ -1,89 +0,0 @@
"""authentik outpost views"""
from typing import Any, Dict, List
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Model
from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404
from django.views import View
from django.views.generic import TemplateView
from guardian.shortcuts import get_objects_for_user
from structlog import get_logger
from authentik.core.models import User
from authentik.outposts.controllers.docker import DockerController
from authentik.outposts.models import (
DockerServiceConnection,
KubernetesServiceConnection,
Outpost,
OutpostType,
)
from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesController
LOGGER = get_logger()
def get_object_for_user_or_404(user: User, perm: str, **filters) -> Model:
"""Wrapper that combines get_objects_for_user and get_object_or_404"""
return get_object_or_404(get_objects_for_user(user, perm), **filters)
class DockerComposeView(LoginRequiredMixin, View):
"""Generate docker-compose yaml"""
def get(self, request: HttpRequest, outpost_pk: str) -> HttpResponse:
"""Render docker-compose file"""
outpost: Outpost = get_object_for_user_or_404(
request.user,
"authentik_outposts.view_outpost",
pk=outpost_pk,
)
manifest = ""
if outpost.type == OutpostType.PROXY:
controller = DockerController(outpost, DockerServiceConnection())
manifest = controller.get_static_deployment()
return HttpResponse(manifest, content_type="text/vnd.yaml")
class KubernetesManifestView(LoginRequiredMixin, View):
"""Generate Kubernetes Deployment and SVC for proxy"""
def get(self, request: HttpRequest, outpost_pk: str) -> HttpResponse:
"""Render deployment template"""
outpost: Outpost = get_object_for_user_or_404(
request.user,
"authentik_outposts.view_outpost",
pk=outpost_pk,
)
manifest = ""
if outpost.type == OutpostType.PROXY:
controller = ProxyKubernetesController(
outpost, KubernetesServiceConnection()
)
manifest = controller.get_static_deployment()
return HttpResponse(manifest, content_type="text/vnd.yaml")
class SetupView(LoginRequiredMixin, TemplateView):
"""Setup view"""
def get_template_names(self) -> List[str]:
allowed = ["dc", "custom", "k8s_manual", "k8s_integration"]
setup_type = self.request.GET.get("type", "dc")
if setup_type not in allowed:
setup_type = allowed[0]
return [f"outposts/setup_{setup_type}.html"]
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
kwargs = super().get_context_data(**kwargs)
outpost: Outpost = get_object_for_user_or_404(
self.request.user,
"authentik_outposts.view_outpost",
pk=self.kwargs["outpost_pk"],
)
kwargs.update(
{"host": self.request.build_absolute_uri("/"), "outpost": outpost}
)
return kwargs

View File

@ -7,7 +7,7 @@
<label for="" class="pf-c-form__label"></label>
<div class="c-form__horizontal-group">
<p>
Expression using Python. See <a target="_blank" href="https://goauthentik.io/policies/expression/">here</a> for a list of all variables.
Expression using Python. See <a target="_blank" href="https://goauthentik.io/docs/policies/expression/">here</a> for a list of all variables.
</p>
</div>
</div>

View File

@ -50,6 +50,7 @@ class HaveIBeenPwendPolicy(Policy):
field=self.password_field,
fields=request.context.keys(),
)
return PolicyResult(False, _("Password not set in context"))
password = request.context[self.password_field]
pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec

View File

@ -10,6 +10,16 @@ from authentik.providers.oauth2.generators import generate_client_secret
class TestHIBPPolicy(TestCase):
"""Test HIBP Policy"""
def test_invalid(self):
"""Test without password"""
policy = HaveIBeenPwendPolicy.objects.create(
name="test_invalid",
)
request = PolicyRequest(get_anonymous_user())
result: PolicyResult = policy.passes(request)
self.assertFalse(result.passing)
self.assertEqual(result.messages[0], "Password not set in context")
def test_false(self):
"""Failing password case"""
policy = HaveIBeenPwendPolicy.objects.create(

View File

@ -50,6 +50,7 @@ class PasswordPolicy(Policy):
field=self.password_field,
fields=request.context.keys(),
)
return PolicyResult(False, _("Password not set in context"))
password = request.context[self.password_field]
filter_regex = []

View File

@ -9,6 +9,21 @@ from authentik.policies.types import PolicyRequest, PolicyResult
class TestPasswordPolicy(TestCase):
"""Test Password Policy"""
def test_invalid(self):
"""Test without password"""
policy = PasswordPolicy.objects.create(
name="test_invalid",
amount_uppercase=1,
amount_lowercase=2,
amount_symbols=3,
length_min=24,
error_message="test message",
)
request = PolicyRequest(get_anonymous_user())
result: PolicyResult = policy.passes(request)
self.assertFalse(result.passing)
self.assertEqual(result.messages[0], "Password not set in context")
def test_false(self):
"""Failing password case"""
policy = PasswordPolicy.objects.create(

View File

@ -7,7 +7,7 @@
<label for="" class="pf-c-form__label"></label>
<div class="c-form__horizontal-group">
<p>
Expression using Python. See <a href="https://goauthentik.io/property-mappings/expression/">here</a> for a list of all variables.
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
</p>
</div>
</div>

View File

@ -0,0 +1,46 @@
"""Test authorize view"""
from django.test import RequestFactory, TestCase
from authentik.flows.models import Flow
from authentik.providers.oauth2.errors import (
AuthorizeError,
ClientIdError,
RedirectUriError,
)
from authentik.providers.oauth2.models import OAuth2Provider
from authentik.providers.oauth2.views.authorize import OAuthAuthorizationParams
class TestViewsAuthorize(TestCase):
"""Test authorize view"""
def setUp(self) -> None:
super().setUp()
self.factory = RequestFactory()
def test_invalid_grant_type(self):
"""Test with invalid grant type"""
with self.assertRaises(AuthorizeError):
request = self.factory.get("/", data={"response_type": "invalid"})
OAuthAuthorizationParams.from_request(request)
def test_invalid_client_id(self):
"""Test invalid client ID"""
with self.assertRaises(ClientIdError):
request = self.factory.get(
"/", data={"response_type": "code", "client_id": "invalid"}
)
OAuthAuthorizationParams.from_request(request)
def test_missing_redirect_uri(self):
"""test missing redirect URI"""
OAuth2Provider.objects.create(
name="test",
client_id="test",
authorization_flow=Flow.objects.first(),
)
with self.assertRaises(RedirectUriError):
request = self.factory.get(
"/", data={"response_type": "code", "client_id": "test"}
)
OAuthAuthorizationParams.from_request(request)

View File

@ -139,7 +139,7 @@ class OAuthAuthorizationParams:
is_open_id = SCOPE_OPENID in self.scope
# Redirect URI validation.
if is_open_id and not self.redirect_uri:
if not self.redirect_uri:
LOGGER.warning("Missing redirect uri.")
raise RedirectUriError()
if self.redirect_uri.lower() not in [

View File

@ -1,34 +1,6 @@
# Generated by Django 3.1.1 on 2020-09-30 08:10
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
SCOPE_AK_PROXY_EXPRESSION = """return {
"ak_proxy": {
"user_attributes": user.group_attributes()
}
}"""
def create_proxy_scope(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from authentik.providers.proxy.models import SCOPE_AK_PROXY, ProxyProvider
ScopeMapping = apps.get_model("authentik_providers_oauth2", "ScopeMapping")
ScopeMapping.objects.update_or_create(
scope_name=SCOPE_AK_PROXY,
defaults={
"name": "Autogenerated OAuth2 Mapping: authentik Proxy",
"scope_name": SCOPE_AK_PROXY,
"description": "",
"expression": SCOPE_AK_PROXY_EXPRESSION,
},
)
for provider in ProxyProvider.objects.all():
provider.set_oauth_defaults()
provider.save()
class Migration(migrations.Migration):
@ -74,5 +46,4 @@ class Migration(migrations.Migration):
verbose_name="HTTP-Basic Username",
),
),
migrations.RunPython(create_proxy_scope),
]

View File

@ -0,0 +1,41 @@
# Generated by Django 3.1.4 on 2020-12-14 09:42
from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
SCOPE_AK_PROXY_EXPRESSION = """return {
"ak_proxy": {
"user_attributes": user.group_attributes()
}
}"""
def create_proxy_scope(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from authentik.providers.proxy.models import SCOPE_AK_PROXY, ProxyProvider
ScopeMapping = apps.get_model("authentik_providers_oauth2", "ScopeMapping")
ScopeMapping.objects.filter(scope_name="pb_proxy").delete()
ScopeMapping.objects.update_or_create(
scope_name=SCOPE_AK_PROXY,
defaults={
"name": "Autogenerated OAuth2 Mapping: authentik Proxy",
"scope_name": SCOPE_AK_PROXY,
"description": "",
"expression": SCOPE_AK_PROXY_EXPRESSION,
},
)
for provider in ProxyProvider.objects.all():
provider.set_oauth_defaults()
provider.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_proxy", "0009_auto_20201007_1721"),
]
operations = [migrations.RunPython(create_proxy_scope)]

View File

@ -7,7 +7,7 @@
<label for="" class="pf-c-form__label"></label>
<div class="c-form__horizontal-group">
<p>
Expression using Python. See <a href="https://goauthentik.io/property-mappings/expression/">here</a> for a list of all variables.
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
</p>
</div>
</div>

View File

@ -0,0 +1,84 @@
"""Test Requests and Responses against schema"""
from base64 import b64encode
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import RequestFactory, TestCase
from guardian.utils import get_anonymous_user
from lxml import etree # nosec
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.assertion import AssertionProcessor
from authentik.providers.saml.processors.request_parser import AuthNRequestParser
from authentik.providers.saml.tests.test_auth_n_request import dummy_get_response
from authentik.sources.saml.models import SAMLSource
from authentik.sources.saml.processors.request import RequestProcessor
class TestSchema(TestCase):
"""Test Requests and Responses against schema"""
def setUp(self):
cert = CertificateKeyPair.objects.first()
self.provider: SAMLProvider = SAMLProvider.objects.create(
authorization_flow=Flow.objects.get(
slug="default-provider-authorization-implicit-consent"
),
acs_url="http://testserver/source/saml/provider/acs/",
signing_kp=cert,
verification_kp=cert,
)
self.provider.property_mappings.set(SAMLPropertyMapping.objects.all())
self.provider.save()
self.source = SAMLSource.objects.create(
slug="provider",
issuer="authentik",
signing_kp=cert,
)
self.factory = RequestFactory()
def test_request_schema(self):
"""Test generated AuthNRequest against Schema"""
http_request = self.factory.get("/")
middleware = SessionMiddleware(dummy_get_response)
middleware.process_request(http_request)
http_request.session.save()
# First create an AuthNRequest
request_proc = RequestProcessor(self.source, http_request, "test_state")
request = request_proc.build_auth_n()
metadata = etree.fromstring(request) # nosec
schema = etree.XMLSchema(
etree.parse("xml/saml-schema-protocol-2.0.xsd")
) # nosec
self.assertTrue(schema.validate(metadata))
def test_response_schema(self):
"""Test generated AuthNRequest against Schema"""
http_request = self.factory.get("/")
http_request.user = get_anonymous_user()
middleware = SessionMiddleware(dummy_get_response)
middleware.process_request(http_request)
http_request.session.save()
# First create an AuthNRequest
request_proc = RequestProcessor(self.source, http_request, "test_state")
request = request_proc.build_auth_n()
# To get an assertion we need a parsed request (parsed by provider)
parsed_request = AuthNRequestParser(self.provider).parse(
b64encode(request.encode()).decode(), "test_state"
)
# Now create a response and convert it to string (provider)
response_proc = AssertionProcessor(self.provider, http_request, parsed_request)
response = response_proc.build_response()
metadata = etree.fromstring(response) # nosec
schema = etree.XMLSchema(etree.parse("xml/saml-schema-protocol-2.0.xsd"))
self.assertTrue(schema.validate(metadata))

View File

@ -1,15 +1,6 @@
"""Small helper functions"""
import uuid
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
from django.template.context import Context
def render_xml(request: HttpRequest, template: str, ctx: Context) -> HttpResponse:
"""Render template with content_type application/xml"""
return render(request, template, context=ctx, content_type="application/xml")
def get_random_id() -> str:
"""Random hex id"""

View File

@ -32,3 +32,10 @@ class TestRecovery(TestCase):
reverse("authentik_recovery:use-token", kwargs={"key": token.key})
)
self.assertEqual(int(self.client.session["_auth_user_id"]), token.user.pk)
def test_recovery_view_invalid(self):
"""Test recovery view with invalid token"""
response = self.client.get(
reverse("authentik_recovery:use-token", kwargs={"key": "abc"})
)
self.assertEqual(response.status_code, 404)

View File

@ -7,13 +7,16 @@ class MessageConsumer(JsonWebsocketConsumer):
"""Consumer which sends django.contrib.messages Messages over WS.
channel_name is saved into cache with user_id, and when a add_message is called"""
session_key: str
def connect(self):
self.accept()
cache.set(f"user_{self.scope['user'].pk}_messages_{self.channel_name}", True)
self.session_key = self.scope["session"].session_key
cache.set(f"user_{self.session_key}_messages_{self.channel_name}", True, None)
# pylint: disable=unused-argument
def disconnect(self, close_code):
cache.delete(f"user_{self.scope['user'].pk}_messages_{self.channel_name}")
cache.delete(f"user_{self.session_key}_messages_{self.channel_name}")
def event_update(self, event: dict):
"""Event handler which is called by Messages Storage backend"""

View File

@ -16,7 +16,7 @@ class ChannelsStorage(FallbackStorage):
self.channel = get_channel_layer()
def _store(self, messages: list[Message], response, *args, **kwargs):
prefix = f"user_{self.request.user.pk}_messages_"
prefix = f"user_{self.request.session.session_key}_messages_"
keys = cache.keys(f"{prefix}*")
if len(keys) < 1:
return super()._store(messages, response, *args, **kwargs)

View File

@ -4,7 +4,7 @@ from django.conf import settings
from authentik.lib.config import CONFIG
class PytestTestRunner:
class PytestTestRunner: # pragma: no cover
"""Runs pytest to discover and run tests."""
def __init__(self, verbosity=1, failfast=False, keepdb=False, **_):

View File

@ -7,7 +7,7 @@
<label for="" class="pf-c-form__label"></label>
<div class="c-form__horizontal-group">
<p>
Expression using Python. See <a href="https://goauthentik.io/property-mappings/expression/">here</a> for a list of all variables.
Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables.
</p>
</div>
</div>

View File

@ -0,0 +1,41 @@
"""Discord Type tests"""
from django.test import TestCase
from authentik.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
from authentik.sources.oauth.types.discord import DiscordOAuth2Callback
# https://discord.com/developers/docs/resources/user#user-object
DISCORD_USER = {
"id": "80351110224678912",
"username": "Nelly",
"discriminator": "1337",
"avatar": "8342729096ea3675442027381ff50dfe",
"verified": True,
"email": "nelly@discord.com",
"flags": 64,
"premium_type": 1,
"public_flags": 64,
}
class TestTypeGitHub(TestCase):
"""OAuth Source tests"""
def setUp(self):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
authorization_url="",
profile_url="",
consumer_key="",
)
def test_enroll_context(self):
"""Test GitHub Enrollment context"""
ak_context = DiscordOAuth2Callback().get_user_enroll_context(
self.source, UserOAuthSourceConnection(), DISCORD_USER
)
self.assertEqual(ak_context["username"], DISCORD_USER["username"])
self.assertEqual(ak_context["email"], DISCORD_USER["email"])
self.assertEqual(ak_context["name"], DISCORD_USER["username"])

View File

@ -0,0 +1,71 @@
"""GitHub Type tests"""
from django.test import TestCase
from authentik.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
from authentik.sources.oauth.types.github import GitHubOAuth2Callback
# https://developer.github.com/v3/users/#get-the-authenticated-user
GITHUB_USER = {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": False,
"name": "monalisa octocat",
"company": "GitHub",
"blog": "https://github.com/blog",
"location": "San Francisco",
"email": "octocat@github.com",
"hireable": False,
"bio": "There once was...",
"twitter_username": "monatheoctocat",
"public_repos": 2,
"public_gists": 1,
"followers": 20,
"following": 0,
"created_at": "2008-01-14T04:33:35Z",
"updated_at": "2008-01-14T04:33:35Z",
"private_gists": 81,
"total_private_repos": 100,
"owned_private_repos": 100,
"disk_usage": 10000,
"collaborators": 8,
"two_factor_authentication": True,
"plan": {"name": "Medium", "space": 400, "private_repos": 20, "collaborators": 0},
}
class TestTypeGitHub(TestCase):
"""OAuth Source tests"""
def setUp(self):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
authorization_url="",
profile_url="",
consumer_key="",
)
def test_enroll_context(self):
"""Test GitHub Enrollment context"""
ak_context = GitHubOAuth2Callback().get_user_enroll_context(
self.source, UserOAuthSourceConnection(), GITHUB_USER
)
self.assertEqual(ak_context["username"], GITHUB_USER["login"])
self.assertEqual(ak_context["email"], GITHUB_USER["email"])
self.assertEqual(ak_context["name"], GITHUB_USER["name"])

View File

@ -0,0 +1,112 @@
"""Twitter Type tests"""
from django.test import Client, TestCase
from authentik.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
from authentik.sources.oauth.types.twitter import TwitterOAuthCallback
# https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/manage-account-settings/ \
# api-reference/get-account-verify_credentials
TWITTER_USER = {
"contributors_enabled": True,
"created_at": "Sat May 09 17:58:22 +0000 2009",
"default_profile": False,
"default_profile_image": False,
"description": "I taught your phone that thing you like.",
"favourites_count": 588,
"follow_request_sent": None,
"followers_count": 10625,
"following": None,
"friends_count": 1181,
"geo_enabled": True,
"id": 38895958,
"id_str": "38895958",
"is_translator": False,
"lang": "en",
"listed_count": 190,
"location": "San Francisco",
"name": "Sean Cook",
"notifications": None,
"profile_background_color": "1A1B1F",
"profile_background_image_url": "",
"profile_background_image_url_https": "",
"profile_background_tile": True,
"profile_image_url": "",
"profile_image_url_https": "",
"profile_link_color": "2FC2EF",
"profile_sidebar_border_color": "181A1E",
"profile_sidebar_fill_color": "252429",
"profile_text_color": "666666",
"profile_use_background_image": True,
"protected": False,
"screen_name": "theSeanCook",
"show_all_inline_media": True,
"status": {
"contributors": None,
"coordinates": {"coordinates": [-122.45037293, 37.76484123], "type": "Point"},
"created_at": "Tue Aug 28 05:44:24 +0000 2012",
"favorited": False,
"geo": {"coordinates": [37.76484123, -122.45037293], "type": "Point"},
"id": 240323931419062272,
"id_str": "240323931419062272",
"in_reply_to_screen_name": "messl",
"in_reply_to_status_id": 240316959173009410,
"in_reply_to_status_id_str": "240316959173009410",
"in_reply_to_user_id": 18707866,
"in_reply_to_user_id_str": "18707866",
"place": {
"attributes": {},
"bounding_box": {
"coordinates": [
[
[-122.45778216, 37.75932999],
[-122.44248216, 37.75932999],
[-122.44248216, 37.76752899],
[-122.45778216, 37.76752899],
]
],
"type": "Polygon",
},
"country": "United States",
"country_code": "US",
"full_name": "Ashbury Heights, San Francisco",
"id": "866269c983527d5a",
"name": "Ashbury Heights",
"place_type": "neighborhood",
"url": "http://api.twitter.com/1/geo/id/866269c983527d5a.json",
},
"retweet_count": 0,
"retweeted": False,
"source": "Twitter for iPhone",
"text": "@messl congrats! So happy for all 3 of you.",
"truncated": False,
},
"statuses_count": 2609,
"time_zone": "Pacific Time (US & Canada)",
"url": None,
"utc_offset": -28800,
"verified": False,
}
class TestTypeGitHub(TestCase):
"""OAuth Source tests"""
def setUp(self):
self.client = Client()
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
authorization_url="",
profile_url="",
consumer_key="",
)
def test_enroll_context(self):
"""Test Twitter Enrollment context"""
ak_context = TwitterOAuthCallback().get_user_enroll_context(
self.source, UserOAuthSourceConnection(), TWITTER_USER
)
self.assertEqual(ak_context["username"], TWITTER_USER["screen_name"])
self.assertEqual(ak_context["email"], TWITTER_USER.get("email", None))
self.assertEqual(ak_context["name"], TWITTER_USER["name"])

View File

@ -1,15 +1,14 @@
"""OAuth Source tests"""
from django.shortcuts import reverse
from django.test import Client, TestCase
from django.test import TestCase
from authentik.sources.oauth.models import OAuthSource
class OAuthSourceTests(TestCase):
class TestOAuthSource(TestCase):
"""OAuth Source tests"""
def setUp(self):
self.client = Client()
self.source = OAuthSource.objects.create(
name="test",
slug="test",

View File

@ -11,7 +11,7 @@ from authentik.sources.oauth.views.redirect import OAuthRedirect
class DiscordOAuthRedirect(OAuthRedirect):
"""Discord OAuth2 Redirect"""
def get_additional_parameters(self, source):
def get_additional_parameters(self, source): # pragma: no cover
return {
"scope": "email identify",
}

View File

@ -14,7 +14,7 @@ from authentik.sources.oauth.views.redirect import OAuthRedirect
class FacebookOAuthRedirect(OAuthRedirect):
"""Facebook OAuth2 Redirect"""
def get_additional_parameters(self, source):
def get_additional_parameters(self, source): # pragma: no cover
return {
"scope": "email",
}

View File

@ -11,7 +11,7 @@ from authentik.sources.oauth.views.redirect import OAuthRedirect
class GoogleOAuthRedirect(OAuthRedirect):
"""Google OAuth2 Redirect"""
def get_additional_parameters(self, source):
def get_additional_parameters(self, source): # pragma: no cover
return {
"scope": "email profile",
}

View File

@ -11,7 +11,7 @@ from authentik.sources.oauth.views.redirect import OAuthRedirect
class OpenIDConnectOAuthRedirect(OAuthRedirect):
"""OpenIDConnect OAuth2 Redirect"""
def get_additional_parameters(self, source: OAuthSource):
def get_additional_parameters(self, source: OAuthSource): # pragma: no cover
return {
"scope": "openid email profile",
}

View File

@ -14,7 +14,7 @@ from authentik.sources.oauth.views.redirect import OAuthRedirect
class RedditOAuthRedirect(OAuthRedirect):
"""Reddit OAuth2 Redirect"""
def get_additional_parameters(self, source):
def get_additional_parameters(self, source): # pragma: no cover
return {
"scope": "identity",
"duration": "permanent",

View File

@ -18,6 +18,6 @@ class TwitterOAuthCallback(OAuthCallback):
) -> Dict[str, Any]:
return {
"username": info.get("screen_name"),
"email": info.get("email"),
"email": info.get("email", None),
"name": info.get("name"),
}

View File

@ -1,26 +0,0 @@
"""SAML Source tests"""
from defusedxml import ElementTree
from django.test import RequestFactory, TestCase
from authentik.crypto.models import CertificateKeyPair
from authentik.sources.saml.models import SAMLSource
from authentik.sources.saml.processors.metadata import MetadataProcessor
class TestMetadataProcessor(TestCase):
"""Test MetadataProcessor"""
def setUp(self):
self.source = SAMLSource.objects.create(
slug="provider",
issuer="authentik",
signing_kp=CertificateKeyPair.objects.first(),
)
self.factory = RequestFactory()
def test_metadata(self):
"""Test Metadata generation being valid"""
request = self.factory.get("/")
xml = MetadataProcessor(self.source, request).build_entity_descriptor()
metadata = ElementTree.fromstring(xml)
self.assertEqual(metadata.attrib["entityID"], "authentik")

View File

View File

@ -0,0 +1,55 @@
"""SAML Source tests"""
from defusedxml import ElementTree
from django.test import RequestFactory, TestCase
from lxml import etree # nosec
from authentik.crypto.models import CertificateKeyPair
from authentik.sources.saml.models import SAMLSource
from authentik.sources.saml.processors.metadata import MetadataProcessor
class TestMetadataProcessor(TestCase):
"""Test MetadataProcessor"""
def setUp(self):
self.factory = RequestFactory()
def test_metadata_schema(self):
"""Test Metadata generation being valid"""
source = SAMLSource.objects.create(
slug="provider",
issuer="authentik",
signing_kp=CertificateKeyPair.objects.first(),
)
request = self.factory.get("/")
xml = MetadataProcessor(source, request).build_entity_descriptor()
metadata = etree.fromstring(xml) # nosec
schema = etree.XMLSchema(
etree.parse("xml/saml-schema-metadata-2.0.xsd")
) # nosec
self.assertTrue(schema.validate(metadata))
def test_metadata(self):
"""Test Metadata generation being valid"""
source = SAMLSource.objects.create(
slug="provider",
issuer="authentik",
signing_kp=CertificateKeyPair.objects.first(),
)
request = self.factory.get("/")
xml = MetadataProcessor(source, request).build_entity_descriptor()
metadata = ElementTree.fromstring(xml)
self.assertEqual(metadata.attrib["entityID"], "authentik")
def test_metadata_without_signautre(self):
"""Test Metadata generation being valid"""
source = SAMLSource.objects.create(
slug="provider",
issuer="authentik",
# signing_kp=CertificateKeyPair.objects.first(),
)
request = self.factory.get("/")
xml = MetadataProcessor(source, request).build_entity_descriptor()
metadata = ElementTree.fromstring(xml)
self.assertEqual(metadata.attrib["entityID"], "authentik")

View File

@ -87,6 +87,7 @@ class TestUserWriteStage(TestCase):
"username": "test-user-new",
"password": new_password,
"attribute_some-custom-attribute": "test",
"some_ignored_attribute": "bar",
}
session = self.client.session
session[SESSION_KEY_PLAN] = plan
@ -109,6 +110,7 @@ class TestUserWriteStage(TestCase):
self.assertTrue(user_qs.exists())
self.assertTrue(user_qs.first().check_password(new_password))
self.assertEqual(user_qs.first().attributes["some-custom-attribute"], "test")
self.assertNotIn("some_ignored_attribute", user_qs.first().attributes)
@patch(
"authentik.flows.views.to_stage_response",

View File

@ -10,8 +10,8 @@ services:
- internal
environment:
- POSTGRES_PASSWORD=${PG_PASS:-thisisnotagoodpassword}
- POSTGRES_USER=authentik
- POSTGRES_DB=authentik
- POSTGRES_USER=${PG_USER:-authentik}
- POSTGRES_DB=${PG_DB:-authentik}
env_file:
- .env
redis:
@ -19,11 +19,13 @@ services:
networks:
- internal
server:
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc3}
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.1-stable}
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
volumes:
- ./media:/media
@ -42,13 +44,15 @@ services:
env_file:
- .env
worker:
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc3}
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.1-stable}
command: worker
networks:
- internal
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
volumes:
- ./backups:/backups
@ -56,7 +60,7 @@ services:
env_file:
- .env
static:
image: beryju/authentik-static:${AUTHENTIK_TAG:-0.13.0-rc3}
image: beryju/authentik-static:${AUTHENTIK_TAG:-0.13.1-stable}
networks:
- internal
labels:
@ -68,7 +72,7 @@ services:
traefik.http.services.static-service.loadbalancer.healthcheck.path: /
traefik.http.services.static-service.loadbalancer.server.port: '80'
volumes:
- ./media:/media
- ./media:/usr/share/nginx/html/media
traefik:
image: traefik:2.3
command:
@ -81,7 +85,6 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "0.0.0.0:80:80"
- "0.0.0.0:443:443"
- "127.0.0.1:8080:8080"
networks:

View File

@ -4,7 +4,7 @@ name: authentik
home: https://goauthentik.io
sources:
- https://github.com/BeryJu/authentik
version: "0.13.0-rc3"
version: "0.13.1-stable"
icon: https://raw.githubusercontent.com/BeryJu/authentik/master/web/icons/icon.svg
dependencies:
- name: postgresql

View File

@ -4,7 +4,7 @@
|-----------------------------------|-------------------------|-------------|
| image.name | beryju/authentik | Image used to run the authentik server and worker |
| image.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) |
| image.tag | 0.13.0-rc3 | Image tag |
| image.tag | 0.13.1-stable | Image tag |
| image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments |
| serverReplicas | 1 | Replicas for the Server deployment |
| workerReplicas | 1 | Replicas for the Worker deployment |

View File

@ -36,6 +36,10 @@ spec:
backend:
serviceName: {{ $fullName }}-static
servicePort: http
- path: /media/
backend:
serviceName: {{ $fullName }}-static
servicePort: http
- path: /robots.txt
backend:
serviceName: {{ $fullName }}-static

View File

@ -5,7 +5,7 @@ image:
name: beryju/authentik
name_static: beryju/authentik-static
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
tag: 0.13.0-rc3
tag: 0.13.1-stable
pullPolicy: IfNotPresent
serverReplicas: 1

View File

@ -5,12 +5,12 @@ go 1.14
require (
cloud.google.com/go v0.64.0 // indirect
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/getsentry/sentry-go v0.7.0
github.com/go-openapi/errors v0.19.9
github.com/getsentry/sentry-go v0.9.0
github.com/go-openapi/errors v0.19.9 // indirect
github.com/go-openapi/runtime v0.19.24
github.com/go-openapi/strfmt v0.19.11
github.com/go-openapi/swag v0.19.12
github.com/go-openapi/validate v0.19.15
github.com/go-openapi/swag v0.19.12 // indirect
github.com/go-openapi/validate v0.19.15 // indirect
github.com/go-redis/redis/v7 v7.4.0 // indirect
github.com/go-swagger/go-swagger v0.25.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
@ -22,7 +22,7 @@ require (
github.com/oauth2-proxy/oauth2-proxy v1.1.2-0.20200817154438-5fa5b3186f39
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f // indirect
github.com/recws-org/recws v1.2.1
github.com/recws-org/recws v1.2.2
github.com/sirupsen/logrus v1.7.0
github.com/spf13/afero v1.4.1 // indirect
github.com/spf13/cast v1.3.1 // indirect

View File

@ -35,13 +35,17 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BeryJu/authentik v0.0.0-20201213234502-f0f32453882b h1:tLc7ERt2fWSu14nXdsER4EP62KUPXwAB0OeLVAA4Rx0=
github.com/BeryJu/authentik v0.0.0-20201214075318-41f9097592da h1:XB/MCgb0K+ngEETjBYKGiXcN2des8YtANetYboeT4Lg=
github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw=
github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc=
github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
@ -139,6 +143,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/sentry-go v0.7.0 h1:MR2yfR4vFfv/2+iBuSnkdQwVg7N9cJzihZ6KJu7srwQ=
github.com/getsentry/sentry-go v0.7.0/go.mod h1:pLFpD2Y5RHIKF9Bw3KH6/68DeN2K/XBJd8awjdPnUwg=
github.com/getsentry/sentry-go v0.9.0 h1:KIfpY/D9hX3gWAEd3d8z6ImuHNWtqEsjlpdF8zXFsHM=
github.com/getsentry/sentry-go v0.9.0/go.mod h1:kELm/9iCblqUYh+ZRML7PNdCvEuw24wBvJPYyi86cws=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
@ -409,6 +415,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@ -438,9 +446,14 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
@ -448,6 +461,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
@ -496,6 +510,7 @@ github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvB
github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s=
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@ -519,8 +534,11 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@ -577,6 +595,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/recws-org/recws v1.2.1 h1:bYocRkAsS71hlQ9AMCVS+hYXHEgEyQsAbYKXf394gZ8=
github.com/recws-org/recws v1.2.1/go.mod h1:SxTgwQU/jqYSzEgUh4ifDxq/7enApS150f8nZ5Sczk8=
github.com/recws-org/recws v1.2.2 h1:TkyyCEgMjsr1D2fnutY/DPhGnUKCLpJeXDAGy6rLmGE=
github.com/recws-org/recws v1.2.2/go.mod h1:SxTgwQU/jqYSzEgUh4ifDxq/7enApS150f8nZ5Sczk8=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@ -584,6 +604,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@ -711,6 +732,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
@ -1046,6 +1068,7 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -1070,6 +1093,7 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -59,6 +59,7 @@ func getCommonOptions() *options.Options {
}
func doGlobalSetup(config map[string]interface{}) {
log.SetFormatter(&log.JSONFormatter{})
switch config[ConfigLogLevel].(string) {
case "debug":
log.SetLevel(log.DebugLevel)

View File

@ -1,3 +1,3 @@
package pkg
const VERSION = "0.13.0-rc3"
const VERSION = "0.13.1-stable"

View File

@ -7087,6 +7087,9 @@ definitions:
type: boolean
url:
title: Url
description: Can be in the format of 'unix://<path>' when connecting to a
local docker daemon, or 'https://<hostname>:2376' when connecting to a remote
system.
type: string
minLength: 1
tls_verification:

View File

@ -0,0 +1,95 @@
"""outpost tests"""
from shutil import rmtree
from tempfile import mkdtemp
from time import sleep
from django.test import TestCase
from docker import DockerClient, from_env
from docker.models.containers import Container
from docker.types.healthcheck import Healthcheck
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow
from authentik.outposts.apps import AuthentikOutpostConfig
from authentik.outposts.controllers.docker import DockerController
from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostType
from authentik.providers.proxy.models import ProxyProvider
class OutpostDockerTests(TestCase):
"""Test Docker Controllers"""
def _start_container(self, ssl_folder: str) -> Container:
client: DockerClient = from_env()
container = client.containers.run(
image="docker.beryju.org/proxy/library/docker:dind",
detach=True,
network_mode="host",
remove=True,
privileged=True,
healthcheck=Healthcheck(
test=["CMD", "docker", "info"],
interval=5 * 100 * 1000000,
start_period=5 * 100 * 1000000,
),
environment={"DOCKER_TLS_CERTDIR": "/ssl"},
volumes={
f"{ssl_folder}/": {
"bind": "/ssl",
}
},
)
while True:
container.reload()
status = container.attrs.get("State", {}).get("Health", {}).get("Status")
if status == "healthy":
return container
sleep(1)
def setUp(self):
super().setUp()
self.ssl_folder = mkdtemp()
self.container = self._start_container(self.ssl_folder)
# Ensure that local connection have been created
AuthentikOutpostConfig.init_local_connection()
self.provider: ProxyProvider = ProxyProvider.objects.create(
name="test",
internal_host="http://localhost",
external_host="http://localhost",
authorization_flow=Flow.objects.first(),
)
authentication_kp = CertificateKeyPair.objects.create(
name="docker-authentication",
certificate_data=open(f"{self.ssl_folder}/client/cert.pem").read(),
key_data=open(f"{self.ssl_folder}/client/key.pem").read(),
)
verification_kp = CertificateKeyPair.objects.create(
name="docker-verification",
certificate_data=open(f"{self.ssl_folder}/client/ca.pem").read(),
)
self.service_connection = DockerServiceConnection.objects.create(
url="https://localhost:2376",
tls_verification=verification_kp,
tls_authentication=authentication_kp,
)
self.outpost: Outpost = Outpost.objects.create(
name="test",
type=OutpostType.PROXY,
service_connection=self.service_connection,
)
self.outpost.providers.add(self.provider)
self.outpost.save()
def tearDown(self) -> None:
super().tearDown()
self.container.kill()
try:
rmtree(self.ssl_folder)
except PermissionError:
pass
def test_docker_controller(self):
"""test that deployment requires update"""
controller = DockerController(self.outpost, self.service_connection)
controller.up()
controller.down()

View File

@ -8,3 +8,4 @@ FROM nginx
COPY --from=npm-builder /static/robots.txt /usr/share/nginx/html/robots.txt
COPY --from=npm-builder /static/dist/ /usr/share/nginx/html/static/dist/
COPY --from=npm-builder /static/authentik/ /usr/share/nginx/html/static/authentik/

190
web/package-lock.json generated
View File

@ -102,14 +102,14 @@
}
},
"@patternfly/patternfly": {
"version": "4.65.6",
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.65.6.tgz",
"integrity": "sha512-dENO2nZbf5SoEH68coW9U+6FpZmdVnFVjztl7rUeWUPSBUuF1eWld5LT03Q6PVoZuWqqbJxFJodyFKwLb+L9vw=="
"version": "4.70.2",
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.70.2.tgz",
"integrity": "sha512-XKCHnOjx1JThY3s98AJhsApSsGHPvEdlY7r+b18OecqUnmThVGw3nslzYYrwfCGlJ/xQtV5so29SduH2/uhHzA=="
},
"@rollup/plugin-typescript": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.0.0.tgz",
"integrity": "sha512-2L/kKvM5U4VOm+yVMvPIBF3yMZtQUyopf4YIT+KQbqZBZ8Fsdm7X6yeezy92PMyvvHQG1Pa322MVwxPojQvukA==",
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.1.0.tgz",
"integrity": "sha512-pyQlcGQYRsONUDwXK3ckGPHjPzmjlq4sinzr7emW8ZMb2oZjg9WLcdcP8wyHSvBjvHrLzMayyPy079RROqb4vw==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
@ -287,9 +287,9 @@
}
},
"@types/chart.js": {
"version": "2.9.28",
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.28.tgz",
"integrity": "sha512-9YYhsxRngRJb0dkuaU5BezkF+zvvVHnwdRw+rtlahtFb4zqNf9YSgWsOq+dLYeh0fqsWmHUYLR64eNigh02F+w==",
"version": "2.9.29",
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.29.tgz",
"integrity": "sha512-WOZMitUU3gHDM0oQsCsVivX+oDsIki93szcTmmUPBm39cCvAELBjokjSDVOoA3xiIEbb+jp17z/3S2tIqruwOQ==",
"requires": {
"moment": "^2.10.2"
}
@ -393,156 +393,70 @@
}
},
"@typescript-eslint/eslint-plugin": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.1.tgz",
"integrity": "sha512-QRLDSvIPeI1pz5tVuurD+cStNR4sle4avtHhxA+2uyixWGFjKzJ+EaFVRW6dA/jOgjV5DTAjOxboQkRDE8cRlQ==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.10.0.tgz",
"integrity": "sha512-h6/V46o6aXpKRlarP1AiJEXuCJ7cMQdlpfMDrcllIgX3dFkLwEBTXAoNP98ZoOmqd1xvymMVRAI4e7yVvlzWEg==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "4.9.1",
"@typescript-eslint/scope-manager": "4.9.1",
"@typescript-eslint/experimental-utils": "4.10.0",
"@typescript-eslint/scope-manager": "4.10.0",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
"regexpp": "^3.0.0",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"dependencies": {
"@typescript-eslint/scope-manager": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz",
"integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/visitor-keys": "4.9.1"
}
},
"@typescript-eslint/types": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz",
"integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==",
"dev": true
},
"@typescript-eslint/visitor-keys": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz",
"integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"eslint-visitor-keys": "^2.0.0"
}
}
}
},
"@typescript-eslint/experimental-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.1.tgz",
"integrity": "sha512-c3k/xJqk0exLFs+cWSJxIjqLYwdHCuLWhnpnikmPQD2+NGAx9KjLYlBDcSI81EArh9FDYSL6dslAUSwILeWOxg==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.10.0.tgz",
"integrity": "sha512-opX+7ai1sdWBOIoBgpVJrH5e89ra1KoLrJTz0UtWAa4IekkKmqDosk5r6xqRaNJfCXEfteW4HXQAwMdx+jjEmw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/scope-manager": "4.9.1",
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/typescript-estree": "4.9.1",
"@typescript-eslint/scope-manager": "4.10.0",
"@typescript-eslint/types": "4.10.0",
"@typescript-eslint/typescript-estree": "4.10.0",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
},
"dependencies": {
"@typescript-eslint/scope-manager": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz",
"integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/visitor-keys": "4.9.1"
}
},
"@typescript-eslint/types": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz",
"integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz",
"integrity": "sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/visitor-keys": "4.9.1",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
"lodash": "^4.17.15",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz",
"integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"eslint-visitor-keys": "^2.0.0"
}
},
"globby": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
"integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.1.1",
"ignore": "^5.1.4",
"merge2": "^1.3.0",
"slash": "^3.0.0"
}
}
}
},
"@typescript-eslint/parser": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.9.1.tgz",
"integrity": "sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.10.0.tgz",
"integrity": "sha512-amBvUUGBMadzCW6c/qaZmfr3t9PyevcSWw7hY2FuevdZVp5QPw/K76VSQ5Sw3BxlgYCHZcK6DjIhSZK0PQNsQg==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "4.9.1",
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/typescript-estree": "4.9.1",
"@typescript-eslint/scope-manager": "4.10.0",
"@typescript-eslint/types": "4.10.0",
"@typescript-eslint/typescript-estree": "4.10.0",
"debug": "^4.1.1"
}
},
"@typescript-eslint/scope-manager": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz",
"integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.10.0.tgz",
"integrity": "sha512-WAPVw35P+fcnOa8DEic0tQUhoJJsgt+g6DEcz257G7vHFMwmag58EfowdVbiNcdfcV27EFR0tUBVXkDoIvfisQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/visitor-keys": "4.9.1"
"@typescript-eslint/types": "4.10.0",
"@typescript-eslint/visitor-keys": "4.10.0"
}
},
"@typescript-eslint/types": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz",
"integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.10.0.tgz",
"integrity": "sha512-+dt5w1+Lqyd7wIPMa4XhJxUuE8+YF+vxQ6zxHyhLGHJjHiunPf0wSV8LtQwkpmAsRi1lEOoOIR30FG5S2HS33g==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz",
"integrity": "sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.10.0.tgz",
"integrity": "sha512-mGK0YRp9TOk6ZqZ98F++bW6X5kMTzCRROJkGXH62d2azhghmq+1LNLylkGe6uGUOQzD452NOAEth5VAF6PDo5g==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/visitor-keys": "4.9.1",
"@typescript-eslint/types": "4.10.0",
"@typescript-eslint/visitor-keys": "4.10.0",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
@ -568,12 +482,12 @@
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz",
"integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.10.0.tgz",
"integrity": "sha512-hPyz5qmDMuZWFtHZkjcCpkAKHX8vdu1G3YsCLEd25ryZgnJfj6FQuJ5/O7R+dB1ueszilJmAFMtlU4CA6se3Jg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.9.1",
"@typescript-eslint/types": "4.10.0",
"eslint-visitor-keys": "^2.0.0"
}
},
@ -1215,9 +1129,9 @@
"dev": true
},
"eslint-plugin-lit": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.2.4.tgz",
"integrity": "sha512-LfmtuaW9ZcE8R2ji5cMj+SG5bSjEY+IBexuAOKKE+IUB8b6N0AnhVATbfaAX5V2KibeKvIBit2Xpo3QabpeiuA==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz",
"integrity": "sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q==",
"dev": true,
"requires": {
"parse5": "^6.0.1",
@ -2680,9 +2594,9 @@
}
},
"rollup": {
"version": "2.34.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.2.tgz",
"integrity": "sha512-mvtQLqu3cNeoctS+kZ09iOPxrc1P1/Bt1z15enuQ5feyKOdM3MJAVFjjsygurDpSWn530xB4AlA83TWIzRstXA==",
"version": "2.35.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz",
"integrity": "sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==",
"requires": {
"fsevents": "~2.1.2"
}
@ -3317,9 +3231,9 @@
"dev": true
},
"typescript": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
"integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
"dev": true
},
"uglify-js": {

View File

@ -8,35 +8,35 @@
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.15.1",
"@patternfly/patternfly": "^4.65.6",
"@patternfly/patternfly": "^4.70.2",
"@sentry/browser": "^5.29.0",
"@sentry/tracing": "^5.29.0",
"@types/chart.js": "^2.9.28",
"@types/chart.js": "^2.9.29",
"@types/codemirror": "0.0.102",
"chart.js": "^2.9.4",
"codemirror": "^5.58.3",
"construct-style-sheets-polyfill": "^2.4.3",
"lit-element": "^2.4.0",
"lit-html": "^1.3.0",
"rollup": "^2.34.2",
"rollup": "^2.35.1",
"rollup-plugin-copy": "^3.3.0",
"rollup-plugin-cssimport": "^1.0.2",
"rollup-plugin-external-globals": "^0.6.1",
"tslib": "^2.0.3"
},
"devDependencies": {
"@rollup/plugin-typescript": "^8.0.0",
"@typescript-eslint/eslint-plugin": "^4.9.1",
"@typescript-eslint/parser": "^4.9.1",
"@rollup/plugin-typescript": "^8.1.0",
"@typescript-eslint/eslint-plugin": "^4.10.0",
"@typescript-eslint/parser": "^4.10.0",
"eslint": "^7.15.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-lit": "^1.2.4",
"eslint-plugin-lit": "^1.3.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-minify-html-literals": "^1.2.5",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2",
"ts-lit-plugin": "^1.2.1",
"typescript": "^4.1.2"
"typescript": "^4.1.3"
}
}

View File

@ -154,6 +154,9 @@ select[multiple] {
background-color: var(--ak-dark-background-light);
color: var(--ak-dark-foreground);
}
.pf-c-form-control[readonly] {
background-color: var(--ak-dark-background-light);
}
.pf-c-button.pf-m-control {
--pf-c-button--after--BorderColor: var(--ak-dark-background-lighter) var(--ak-dark-background-lighter) var(--pf-c-button--m-control--after--BorderBottomColor) var(--ak-dark-background-lighter);
background-color: var(--ak-dark-background-light);

View File

@ -28,4 +28,4 @@ export const ColorStyles = css`
background-color: var(--pf-global--danger-color--100);
}
`;
export const VERSION = "0.13.0-rc3";
export const VERSION = "0.13.1-stable";

View File

@ -33,6 +33,7 @@ export class SidebarBrand extends LitElement {
.pf-c-brand img {
width: 100%;
padding: 0 .5rem;
height: 42px;
}
`,
];

View File

@ -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 deploy a different version run `echo AUTHENTIK_TAG=0.13.0-rc3 >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=0.13.1-stable >> .env`
If this is a fresh authentik install run the following commands to generate a password:

View File

@ -22,7 +22,7 @@ image:
name: beryju/authentik
name_static: beryju/authentik-static
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
tag: 0.13.0-rc3
tag: 0.13.1-stable
serverReplicas: 1
workerReplicas: 1

View File

@ -12,7 +12,8 @@ After a long back and forth, we've finally switched to a more permanent name. Wh
In this initial release, this brings features such as a refresh button, a generally better User experience due to shorter loading times
and fewer visual context changes.
- The web interface now has a darkmode, which is enabled automatically based on your Operating system.
- The web interface now has a darkmode, which is enabled automatically based on your Operating system darkmode.
- Application Icons can now be uploaded directly to authentik, rather than just being loaded from a URL
## Smaller changes
@ -34,6 +35,13 @@ If you decided to rename the folder you're running the docker-compose file from,
The only manual change you have to do is replace the `PASSBOOK_` prefix in your `.env` file, so `PASSBOOK_SECRET_KEY` gets changed to `AUTHENTIK_SECRET_KEY`.
Additionally, the database name and username have to be changed, so add this block to your `.env` file:
```
PG_USER=passbook
PG_DB=passbook
```
Afterwards, you can simply run `docker-compose up -d` and then the normal upgrade command of `docker-compose run --rm server migrate`.
### Kubernetes

View File

@ -14,7 +14,6 @@ module.exports = {
alt: "authentik logo",
src: "img/icon_left_brand.svg",
},
hideOnScroll: true,
items: [
{
to: "docs/",

View File

@ -0,0 +1,283 @@
<?xml version="1.0" encoding="US-ASCII"?>
<schema
targetNamespace="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
elementFormDefault="unqualified"
attributeFormDefault="unqualified"
blockDefault="substitution"
version="2.0">
<import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation="xmldsig-core-schema.xsd"/>
<import namespace="http://www.w3.org/2001/04/xmlenc#"
schemaLocation="xenc-schema.xsd"/>
<annotation>
<documentation>
Document identifier: saml-schema-assertion-2.0
Location: http://docs.oasis-open.org/security/saml/v2.0/
Revision history:
V1.0 (November, 2002):
Initial Standard Schema.
V1.1 (September, 2003):
Updates within the same V1.0 namespace.
V2.0 (March, 2005):
New assertion schema for SAML V2.0 namespace.
</documentation>
</annotation>
<attributeGroup name="IDNameQualifiers">
<attribute name="NameQualifier" type="string" use="optional"/>
<attribute name="SPNameQualifier" type="string" use="optional"/>
</attributeGroup>
<element name="BaseID" type="saml:BaseIDAbstractType"/>
<complexType name="BaseIDAbstractType" abstract="true">
<attributeGroup ref="saml:IDNameQualifiers"/>
</complexType>
<element name="NameID" type="saml:NameIDType"/>
<complexType name="NameIDType">
<simpleContent>
<extension base="string">
<attributeGroup ref="saml:IDNameQualifiers"/>
<attribute name="Format" type="anyURI" use="optional"/>
<attribute name="SPProvidedID" type="string" use="optional"/>
</extension>
</simpleContent>
</complexType>
<complexType name="EncryptedElementType">
<sequence>
<element ref="xenc:EncryptedData"/>
<element ref="xenc:EncryptedKey" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="EncryptedID" type="saml:EncryptedElementType"/>
<element name="Issuer" type="saml:NameIDType"/>
<element name="AssertionIDRef" type="NCName"/>
<element name="AssertionURIRef" type="anyURI"/>
<element name="Assertion" type="saml:AssertionType"/>
<complexType name="AssertionType">
<sequence>
<element ref="saml:Issuer"/>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="saml:Subject" minOccurs="0"/>
<element ref="saml:Conditions" minOccurs="0"/>
<element ref="saml:Advice" minOccurs="0"/>
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="saml:Statement"/>
<element ref="saml:AuthnStatement"/>
<element ref="saml:AuthzDecisionStatement"/>
<element ref="saml:AttributeStatement"/>
</choice>
</sequence>
<attribute name="Version" type="string" use="required"/>
<attribute name="ID" type="ID" use="required"/>
<attribute name="IssueInstant" type="dateTime" use="required"/>
</complexType>
<element name="Subject" type="saml:SubjectType"/>
<complexType name="SubjectType">
<choice>
<sequence>
<choice>
<element ref="saml:BaseID"/>
<element ref="saml:NameID"/>
<element ref="saml:EncryptedID"/>
</choice>
<element ref="saml:SubjectConfirmation" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<element ref="saml:SubjectConfirmation" maxOccurs="unbounded"/>
</choice>
</complexType>
<element name="SubjectConfirmation" type="saml:SubjectConfirmationType"/>
<complexType name="SubjectConfirmationType">
<sequence>
<choice minOccurs="0">
<element ref="saml:BaseID"/>
<element ref="saml:NameID"/>
<element ref="saml:EncryptedID"/>
</choice>
<element ref="saml:SubjectConfirmationData" minOccurs="0"/>
</sequence>
<attribute name="Method" type="anyURI" use="required"/>
</complexType>
<element name="SubjectConfirmationData" type="saml:SubjectConfirmationDataType"/>
<complexType name="SubjectConfirmationDataType" mixed="true">
<complexContent>
<restriction base="anyType">
<sequence>
<any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="NotBefore" type="dateTime" use="optional"/>
<attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
<attribute name="Recipient" type="anyURI" use="optional"/>
<attribute name="InResponseTo" type="NCName" use="optional"/>
<attribute name="Address" type="string" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</restriction>
</complexContent>
</complexType>
<complexType name="KeyInfoConfirmationDataType" mixed="false">
<complexContent>
<restriction base="saml:SubjectConfirmationDataType">
<sequence>
<element ref="ds:KeyInfo" maxOccurs="unbounded"/>
</sequence>
</restriction>
</complexContent>
</complexType>
<element name="Conditions" type="saml:ConditionsType"/>
<complexType name="ConditionsType">
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="saml:Condition"/>
<element ref="saml:AudienceRestriction"/>
<element ref="saml:OneTimeUse"/>
<element ref="saml:ProxyRestriction"/>
</choice>
<attribute name="NotBefore" type="dateTime" use="optional"/>
<attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
</complexType>
<element name="Condition" type="saml:ConditionAbstractType"/>
<complexType name="ConditionAbstractType" abstract="true"/>
<element name="AudienceRestriction" type="saml:AudienceRestrictionType"/>
<complexType name="AudienceRestrictionType">
<complexContent>
<extension base="saml:ConditionAbstractType">
<sequence>
<element ref="saml:Audience" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="Audience" type="anyURI"/>
<element name="OneTimeUse" type="saml:OneTimeUseType" />
<complexType name="OneTimeUseType">
<complexContent>
<extension base="saml:ConditionAbstractType"/>
</complexContent>
</complexType>
<element name="ProxyRestriction" type="saml:ProxyRestrictionType"/>
<complexType name="ProxyRestrictionType">
<complexContent>
<extension base="saml:ConditionAbstractType">
<sequence>
<element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Count" type="nonNegativeInteger" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="Advice" type="saml:AdviceType"/>
<complexType name="AdviceType">
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="saml:AssertionIDRef"/>
<element ref="saml:AssertionURIRef"/>
<element ref="saml:Assertion"/>
<element ref="saml:EncryptedAssertion"/>
<any namespace="##other" processContents="lax"/>
</choice>
</complexType>
<element name="EncryptedAssertion" type="saml:EncryptedElementType"/>
<element name="Statement" type="saml:StatementAbstractType"/>
<complexType name="StatementAbstractType" abstract="true"/>
<element name="AuthnStatement" type="saml:AuthnStatementType"/>
<complexType name="AuthnStatementType">
<complexContent>
<extension base="saml:StatementAbstractType">
<sequence>
<element ref="saml:SubjectLocality" minOccurs="0"/>
<element ref="saml:AuthnContext"/>
</sequence>
<attribute name="AuthnInstant" type="dateTime" use="required"/>
<attribute name="SessionIndex" type="string" use="optional"/>
<attribute name="SessionNotOnOrAfter" type="dateTime" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="SubjectLocality" type="saml:SubjectLocalityType"/>
<complexType name="SubjectLocalityType">
<attribute name="Address" type="string" use="optional"/>
<attribute name="DNSName" type="string" use="optional"/>
</complexType>
<element name="AuthnContext" type="saml:AuthnContextType"/>
<complexType name="AuthnContextType">
<sequence>
<choice>
<sequence>
<element ref="saml:AuthnContextClassRef"/>
<choice minOccurs="0">
<element ref="saml:AuthnContextDecl"/>
<element ref="saml:AuthnContextDeclRef"/>
</choice>
</sequence>
<choice>
<element ref="saml:AuthnContextDecl"/>
<element ref="saml:AuthnContextDeclRef"/>
</choice>
</choice>
<element ref="saml:AuthenticatingAuthority" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="AuthnContextClassRef" type="anyURI"/>
<element name="AuthnContextDeclRef" type="anyURI"/>
<element name="AuthnContextDecl" type="anyType"/>
<element name="AuthenticatingAuthority" type="anyURI"/>
<element name="AuthzDecisionStatement" type="saml:AuthzDecisionStatementType"/>
<complexType name="AuthzDecisionStatementType">
<complexContent>
<extension base="saml:StatementAbstractType">
<sequence>
<element ref="saml:Action" maxOccurs="unbounded"/>
<element ref="saml:Evidence" minOccurs="0"/>
</sequence>
<attribute name="Resource" type="anyURI" use="required"/>
<attribute name="Decision" type="saml:DecisionType" use="required"/>
</extension>
</complexContent>
</complexType>
<simpleType name="DecisionType">
<restriction base="string">
<enumeration value="Permit"/>
<enumeration value="Deny"/>
<enumeration value="Indeterminate"/>
</restriction>
</simpleType>
<element name="Action" type="saml:ActionType"/>
<complexType name="ActionType">
<simpleContent>
<extension base="string">
<attribute name="Namespace" type="anyURI" use="required"/>
</extension>
</simpleContent>
</complexType>
<element name="Evidence" type="saml:EvidenceType"/>
<complexType name="EvidenceType">
<choice maxOccurs="unbounded">
<element ref="saml:AssertionIDRef"/>
<element ref="saml:AssertionURIRef"/>
<element ref="saml:Assertion"/>
<element ref="saml:EncryptedAssertion"/>
</choice>
</complexType>
<element name="AttributeStatement" type="saml:AttributeStatementType"/>
<complexType name="AttributeStatementType">
<complexContent>
<extension base="saml:StatementAbstractType">
<choice maxOccurs="unbounded">
<element ref="saml:Attribute"/>
<element ref="saml:EncryptedAttribute"/>
</choice>
</extension>
</complexContent>
</complexType>
<element name="Attribute" type="saml:AttributeType"/>
<complexType name="AttributeType">
<sequence>
<element ref="saml:AttributeValue" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Name" type="string" use="required"/>
<attribute name="NameFormat" type="anyURI" use="optional"/>
<attribute name="FriendlyName" type="string" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<element name="AttributeValue" type="anyType" nillable="true"/>
<element name="EncryptedAttribute" type="saml:EncryptedElementType"/>
</schema>

View File

@ -0,0 +1,337 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema
targetNamespace="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="unqualified"
attributeFormDefault="unqualified"
blockDefault="substitution"
version="2.0">
<import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation="xmldsig-core-schema.xsd"/>
<import namespace="http://www.w3.org/2001/04/xmlenc#"
schemaLocation="xenc-schema.xsd"/>
<import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
schemaLocation="saml-schema-assertion-2.0.xsd"/>
<import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="xml.xsd"/>
<annotation>
<documentation>
Document identifier: saml-schema-metadata-2.0
Location: http://docs.oasis-open.org/security/saml/v2.0/
Revision history:
V2.0 (March, 2005):
Schema for SAML metadata, first published in SAML 2.0.
</documentation>
</annotation>
<simpleType name="entityIDType">
<restriction base="anyURI">
<maxLength value="1024"/>
</restriction>
</simpleType>
<complexType name="localizedNameType">
<simpleContent>
<extension base="string">
<attribute ref="xml:lang" use="required"/>
</extension>
</simpleContent>
</complexType>
<complexType name="localizedURIType">
<simpleContent>
<extension base="anyURI">
<attribute ref="xml:lang" use="required"/>
</extension>
</simpleContent>
</complexType>
<element name="Extensions" type="md:ExtensionsType"/>
<complexType final="#all" name="ExtensionsType">
<sequence>
<any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="EndpointType">
<sequence>
<any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Binding" type="anyURI" use="required"/>
<attribute name="Location" type="anyURI" use="required"/>
<attribute name="ResponseLocation" type="anyURI" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<complexType name="IndexedEndpointType">
<complexContent>
<extension base="md:EndpointType">
<attribute name="index" type="unsignedShort" use="required"/>
<attribute name="isDefault" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="EntitiesDescriptor" type="md:EntitiesDescriptorType"/>
<complexType name="EntitiesDescriptorType">
<sequence>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="md:Extensions" minOccurs="0"/>
<choice minOccurs="1" maxOccurs="unbounded">
<element ref="md:EntityDescriptor"/>
<element ref="md:EntitiesDescriptor"/>
</choice>
</sequence>
<attribute name="validUntil" type="dateTime" use="optional"/>
<attribute name="cacheDuration" type="duration" use="optional"/>
<attribute name="ID" type="ID" use="optional"/>
<attribute name="Name" type="string" use="optional"/>
</complexType>
<element name="EntityDescriptor" type="md:EntityDescriptorType"/>
<complexType name="EntityDescriptorType">
<sequence>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="md:Extensions" minOccurs="0"/>
<choice>
<choice maxOccurs="unbounded">
<element ref="md:RoleDescriptor"/>
<element ref="md:IDPSSODescriptor"/>
<element ref="md:SPSSODescriptor"/>
<element ref="md:AuthnAuthorityDescriptor"/>
<element ref="md:AttributeAuthorityDescriptor"/>
<element ref="md:PDPDescriptor"/>
</choice>
<element ref="md:AffiliationDescriptor"/>
</choice>
<element ref="md:Organization" minOccurs="0"/>
<element ref="md:ContactPerson" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AdditionalMetadataLocation" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="entityID" type="md:entityIDType" use="required"/>
<attribute name="validUntil" type="dateTime" use="optional"/>
<attribute name="cacheDuration" type="duration" use="optional"/>
<attribute name="ID" type="ID" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<element name="Organization" type="md:OrganizationType"/>
<complexType name="OrganizationType">
<sequence>
<element ref="md:Extensions" minOccurs="0"/>
<element ref="md:OrganizationName" maxOccurs="unbounded"/>
<element ref="md:OrganizationDisplayName" maxOccurs="unbounded"/>
<element ref="md:OrganizationURL" maxOccurs="unbounded"/>
</sequence>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<element name="OrganizationName" type="md:localizedNameType"/>
<element name="OrganizationDisplayName" type="md:localizedNameType"/>
<element name="OrganizationURL" type="md:localizedURIType"/>
<element name="ContactPerson" type="md:ContactType"/>
<complexType name="ContactType">
<sequence>
<element ref="md:Extensions" minOccurs="0"/>
<element ref="md:Company" minOccurs="0"/>
<element ref="md:GivenName" minOccurs="0"/>
<element ref="md:SurName" minOccurs="0"/>
<element ref="md:EmailAddress" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:TelephoneNumber" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="contactType" type="md:ContactTypeType" use="required"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<element name="Company" type="string"/>
<element name="GivenName" type="string"/>
<element name="SurName" type="string"/>
<element name="EmailAddress" type="anyURI"/>
<element name="TelephoneNumber" type="string"/>
<simpleType name="ContactTypeType">
<restriction base="string">
<enumeration value="technical"/>
<enumeration value="support"/>
<enumeration value="administrative"/>
<enumeration value="billing"/>
<enumeration value="other"/>
</restriction>
</simpleType>
<element name="AdditionalMetadataLocation" type="md:AdditionalMetadataLocationType"/>
<complexType name="AdditionalMetadataLocationType">
<simpleContent>
<extension base="anyURI">
<attribute name="namespace" type="anyURI" use="required"/>
</extension>
</simpleContent>
</complexType>
<element name="RoleDescriptor" type="md:RoleDescriptorType"/>
<complexType name="RoleDescriptorType" abstract="true">
<sequence>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="md:Extensions" minOccurs="0"/>
<element ref="md:KeyDescriptor" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:Organization" minOccurs="0"/>
<element ref="md:ContactPerson" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="ID" type="ID" use="optional"/>
<attribute name="validUntil" type="dateTime" use="optional"/>
<attribute name="cacheDuration" type="duration" use="optional"/>
<attribute name="protocolSupportEnumeration" type="md:anyURIListType" use="required"/>
<attribute name="errorURL" type="anyURI" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<simpleType name="anyURIListType">
<list itemType="anyURI"/>
</simpleType>
<element name="KeyDescriptor" type="md:KeyDescriptorType"/>
<complexType name="KeyDescriptorType">
<sequence>
<element ref="ds:KeyInfo"/>
<element ref="md:EncryptionMethod" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="use" type="md:KeyTypes" use="optional"/>
</complexType>
<simpleType name="KeyTypes">
<restriction base="string">
<enumeration value="encryption"/>
<enumeration value="signing"/>
</restriction>
</simpleType>
<element name="EncryptionMethod" type="xenc:EncryptionMethodType"/>
<complexType name="SSODescriptorType" abstract="true">
<complexContent>
<extension base="md:RoleDescriptorType">
<sequence>
<element ref="md:ArtifactResolutionService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:SingleLogoutService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:ManageNameIDService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="ArtifactResolutionService" type="md:IndexedEndpointType"/>
<element name="SingleLogoutService" type="md:EndpointType"/>
<element name="ManageNameIDService" type="md:EndpointType"/>
<element name="NameIDFormat" type="anyURI"/>
<element name="IDPSSODescriptor" type="md:IDPSSODescriptorType"/>
<complexType name="IDPSSODescriptorType">
<complexContent>
<extension base="md:SSODescriptorType">
<sequence>
<element ref="md:SingleSignOnService" maxOccurs="unbounded"/>
<element ref="md:NameIDMappingService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AttributeProfile" minOccurs="0" maxOccurs="unbounded"/>
<element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="WantAuthnRequestsSigned" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="SingleSignOnService" type="md:EndpointType"/>
<element name="NameIDMappingService" type="md:EndpointType"/>
<element name="AssertionIDRequestService" type="md:EndpointType"/>
<element name="AttributeProfile" type="anyURI"/>
<element name="SPSSODescriptor" type="md:SPSSODescriptorType"/>
<complexType name="SPSSODescriptorType">
<complexContent>
<extension base="md:SSODescriptorType">
<sequence>
<element ref="md:AssertionConsumerService" maxOccurs="unbounded"/>
<element ref="md:AttributeConsumingService" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="AuthnRequestsSigned" type="boolean" use="optional"/>
<attribute name="WantAssertionsSigned" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="AssertionConsumerService" type="md:IndexedEndpointType"/>
<element name="AttributeConsumingService" type="md:AttributeConsumingServiceType"/>
<complexType name="AttributeConsumingServiceType">
<sequence>
<element ref="md:ServiceName" maxOccurs="unbounded"/>
<element ref="md:ServiceDescription" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:RequestedAttribute" maxOccurs="unbounded"/>
</sequence>
<attribute name="index" type="unsignedShort" use="required"/>
<attribute name="isDefault" type="boolean" use="optional"/>
</complexType>
<element name="ServiceName" type="md:localizedNameType"/>
<element name="ServiceDescription" type="md:localizedNameType"/>
<element name="RequestedAttribute" type="md:RequestedAttributeType"/>
<complexType name="RequestedAttributeType">
<complexContent>
<extension base="saml:AttributeType">
<attribute name="isRequired" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="AuthnAuthorityDescriptor" type="md:AuthnAuthorityDescriptorType"/>
<complexType name="AuthnAuthorityDescriptorType">
<complexContent>
<extension base="md:RoleDescriptorType">
<sequence>
<element ref="md:AuthnQueryService" maxOccurs="unbounded"/>
<element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="AuthnQueryService" type="md:EndpointType"/>
<element name="PDPDescriptor" type="md:PDPDescriptorType"/>
<complexType name="PDPDescriptorType">
<complexContent>
<extension base="md:RoleDescriptorType">
<sequence>
<element ref="md:AuthzService" maxOccurs="unbounded"/>
<element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="AuthzService" type="md:EndpointType"/>
<element name="AttributeAuthorityDescriptor" type="md:AttributeAuthorityDescriptorType"/>
<complexType name="AttributeAuthorityDescriptorType">
<complexContent>
<extension base="md:RoleDescriptorType">
<sequence>
<element ref="md:AttributeService" maxOccurs="unbounded"/>
<element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AttributeProfile" minOccurs="0" maxOccurs="unbounded"/>
<element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="AttributeService" type="md:EndpointType"/>
<element name="AffiliationDescriptor" type="md:AffiliationDescriptorType"/>
<complexType name="AffiliationDescriptorType">
<sequence>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="md:Extensions" minOccurs="0"/>
<element ref="md:AffiliateMember" maxOccurs="unbounded"/>
<element ref="md:KeyDescriptor" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="affiliationOwnerID" type="md:entityIDType" use="required"/>
<attribute name="validUntil" type="dateTime" use="optional"/>
<attribute name="cacheDuration" type="duration" use="optional"/>
<attribute name="ID" type="ID" use="optional"/>
<anyAttribute namespace="##other" processContents="lax"/>
</complexType>
<element name="AffiliateMember" type="md:entityIDType"/>
</schema>

View File

@ -0,0 +1,302 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema
targetNamespace="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
elementFormDefault="unqualified"
attributeFormDefault="unqualified"
blockDefault="substitution"
version="2.0">
<import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
schemaLocation="saml-schema-assertion-2.0.xsd"/>
<import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation="xmldsig-core-schema.xsd"/>
<annotation>
<documentation>
Document identifier: saml-schema-protocol-2.0
Location: http://docs.oasis-open.org/security/saml/v2.0/
Revision history:
V1.0 (November, 2002):
Initial Standard Schema.
V1.1 (September, 2003):
Updates within the same V1.0 namespace.
V2.0 (March, 2005):
New protocol schema based in a SAML V2.0 namespace.
</documentation>
</annotation>
<complexType name="RequestAbstractType" abstract="true">
<sequence>
<element ref="saml:Issuer" minOccurs="0"/>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="samlp:Extensions" minOccurs="0"/>
</sequence>
<attribute name="ID" type="ID" use="required"/>
<attribute name="Version" type="string" use="required"/>
<attribute name="IssueInstant" type="dateTime" use="required"/>
<attribute name="Destination" type="anyURI" use="optional"/>
<attribute name="Consent" type="anyURI" use="optional"/>
</complexType>
<element name="Extensions" type="samlp:ExtensionsType"/>
<complexType name="ExtensionsType">
<sequence>
<any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="StatusResponseType">
<sequence>
<element ref="saml:Issuer" minOccurs="0"/>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="samlp:Extensions" minOccurs="0"/>
<element ref="samlp:Status"/>
</sequence>
<attribute name="ID" type="ID" use="required"/>
<attribute name="InResponseTo" type="NCName" use="optional"/>
<attribute name="Version" type="string" use="required"/>
<attribute name="IssueInstant" type="dateTime" use="required"/>
<attribute name="Destination" type="anyURI" use="optional"/>
<attribute name="Consent" type="anyURI" use="optional"/>
</complexType>
<element name="Status" type="samlp:StatusType"/>
<complexType name="StatusType">
<sequence>
<element ref="samlp:StatusCode"/>
<element ref="samlp:StatusMessage" minOccurs="0"/>
<element ref="samlp:StatusDetail" minOccurs="0"/>
</sequence>
</complexType>
<element name="StatusCode" type="samlp:StatusCodeType"/>
<complexType name="StatusCodeType">
<sequence>
<element ref="samlp:StatusCode" minOccurs="0"/>
</sequence>
<attribute name="Value" type="anyURI" use="required"/>
</complexType>
<element name="StatusMessage" type="string"/>
<element name="StatusDetail" type="samlp:StatusDetailType"/>
<complexType name="StatusDetailType">
<sequence>
<any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="AssertionIDRequest" type="samlp:AssertionIDRequestType"/>
<complexType name="AssertionIDRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<element ref="saml:AssertionIDRef" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="SubjectQuery" type="samlp:SubjectQueryAbstractType"/>
<complexType name="SubjectQueryAbstractType" abstract="true">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<element ref="saml:Subject"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="AuthnQuery" type="samlp:AuthnQueryType"/>
<complexType name="AuthnQueryType">
<complexContent>
<extension base="samlp:SubjectQueryAbstractType">
<sequence>
<element ref="samlp:RequestedAuthnContext" minOccurs="0"/>
</sequence>
<attribute name="SessionIndex" type="string" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="RequestedAuthnContext" type="samlp:RequestedAuthnContextType"/>
<complexType name="RequestedAuthnContextType">
<choice>
<element ref="saml:AuthnContextClassRef" maxOccurs="unbounded"/>
<element ref="saml:AuthnContextDeclRef" maxOccurs="unbounded"/>
</choice>
<attribute name="Comparison" type="samlp:AuthnContextComparisonType" use="optional"/>
</complexType>
<simpleType name="AuthnContextComparisonType">
<restriction base="string">
<enumeration value="exact"/>
<enumeration value="minimum"/>
<enumeration value="maximum"/>
<enumeration value="better"/>
</restriction>
</simpleType>
<element name="AttributeQuery" type="samlp:AttributeQueryType"/>
<complexType name="AttributeQueryType">
<complexContent>
<extension base="samlp:SubjectQueryAbstractType">
<sequence>
<element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="AuthzDecisionQuery" type="samlp:AuthzDecisionQueryType"/>
<complexType name="AuthzDecisionQueryType">
<complexContent>
<extension base="samlp:SubjectQueryAbstractType">
<sequence>
<element ref="saml:Action" maxOccurs="unbounded"/>
<element ref="saml:Evidence" minOccurs="0"/>
</sequence>
<attribute name="Resource" type="anyURI" use="required"/>
</extension>
</complexContent>
</complexType>
<element name="AuthnRequest" type="samlp:AuthnRequestType"/>
<complexType name="AuthnRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<element ref="saml:Subject" minOccurs="0"/>
<element ref="samlp:NameIDPolicy" minOccurs="0"/>
<element ref="saml:Conditions" minOccurs="0"/>
<element ref="samlp:RequestedAuthnContext" minOccurs="0"/>
<element ref="samlp:Scoping" minOccurs="0"/>
</sequence>
<attribute name="ForceAuthn" type="boolean" use="optional"/>
<attribute name="IsPassive" type="boolean" use="optional"/>
<attribute name="ProtocolBinding" type="anyURI" use="optional"/>
<attribute name="AssertionConsumerServiceIndex" type="unsignedShort" use="optional"/>
<attribute name="AssertionConsumerServiceURL" type="anyURI" use="optional"/>
<attribute name="AttributeConsumingServiceIndex" type="unsignedShort" use="optional"/>
<attribute name="ProviderName" type="string" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="NameIDPolicy" type="samlp:NameIDPolicyType"/>
<complexType name="NameIDPolicyType">
<attribute name="Format" type="anyURI" use="optional"/>
<attribute name="SPNameQualifier" type="string" use="optional"/>
<attribute name="AllowCreate" type="boolean" use="optional"/>
</complexType>
<element name="Scoping" type="samlp:ScopingType"/>
<complexType name="ScopingType">
<sequence>
<element ref="samlp:IDPList" minOccurs="0"/>
<element ref="samlp:RequesterID" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="ProxyCount" type="nonNegativeInteger" use="optional"/>
</complexType>
<element name="RequesterID" type="anyURI"/>
<element name="IDPList" type="samlp:IDPListType"/>
<complexType name="IDPListType">
<sequence>
<element ref="samlp:IDPEntry" maxOccurs="unbounded"/>
<element ref="samlp:GetComplete" minOccurs="0"/>
</sequence>
</complexType>
<element name="IDPEntry" type="samlp:IDPEntryType"/>
<complexType name="IDPEntryType">
<attribute name="ProviderID" type="anyURI" use="required"/>
<attribute name="Name" type="string" use="optional"/>
<attribute name="Loc" type="anyURI" use="optional"/>
</complexType>
<element name="GetComplete" type="anyURI"/>
<element name="Response" type="samlp:ResponseType"/>
<complexType name="ResponseType">
<complexContent>
<extension base="samlp:StatusResponseType">
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="saml:Assertion"/>
<element ref="saml:EncryptedAssertion"/>
</choice>
</extension>
</complexContent>
</complexType>
<element name="ArtifactResolve" type="samlp:ArtifactResolveType"/>
<complexType name="ArtifactResolveType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<element ref="samlp:Artifact"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="Artifact" type="string"/>
<element name="ArtifactResponse" type="samlp:ArtifactResponseType"/>
<complexType name="ArtifactResponseType">
<complexContent>
<extension base="samlp:StatusResponseType">
<sequence>
<any namespace="##any" processContents="lax" minOccurs="0"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="ManageNameIDRequest" type="samlp:ManageNameIDRequestType"/>
<complexType name="ManageNameIDRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<choice>
<element ref="saml:NameID"/>
<element ref="saml:EncryptedID"/>
</choice>
<choice>
<element ref="samlp:NewID"/>
<element ref="samlp:NewEncryptedID"/>
<element ref="samlp:Terminate"/>
</choice>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="NewID" type="string"/>
<element name="NewEncryptedID" type="saml:EncryptedElementType"/>
<element name="Terminate" type="samlp:TerminateType"/>
<complexType name="TerminateType"/>
<element name="ManageNameIDResponse" type="samlp:StatusResponseType"/>
<element name="LogoutRequest" type="samlp:LogoutRequestType"/>
<complexType name="LogoutRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<choice>
<element ref="saml:BaseID"/>
<element ref="saml:NameID"/>
<element ref="saml:EncryptedID"/>
</choice>
<element ref="samlp:SessionIndex" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Reason" type="string" use="optional"/>
<attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="SessionIndex" type="string"/>
<element name="LogoutResponse" type="samlp:StatusResponseType"/>
<element name="NameIDMappingRequest" type="samlp:NameIDMappingRequestType"/>
<complexType name="NameIDMappingRequestType">
<complexContent>
<extension base="samlp:RequestAbstractType">
<sequence>
<choice>
<element ref="saml:BaseID"/>
<element ref="saml:NameID"/>
<element ref="saml:EncryptedID"/>
</choice>
<element ref="samlp:NameIDPolicy"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="NameIDMappingResponse" type="samlp:NameIDMappingResponseType"/>
<complexType name="NameIDMappingResponseType">
<complexContent>
<extension base="samlp:StatusResponseType">
<choice>
<element ref="saml:NameID"/>
<element ref="saml:EncryptedID"/>
</choice>
</extension>
</complexContent>
</complexType>
</schema>

146
xml/xenc-schema.xsd Normal file
View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE schema PUBLIC "-//W3C//DTD XMLSchema 200102//EN"
"http://www.w3.org/2001/XMLSchema.dtd"
[
<!ATTLIST schema
xmlns:xenc CDATA #FIXED 'http://www.w3.org/2001/04/xmlenc#'
xmlns:ds CDATA #FIXED 'http://www.w3.org/2000/09/xmldsig#'>
<!ENTITY xenc 'http://www.w3.org/2001/04/xmlenc#'>
<!ENTITY % p ''>
<!ENTITY % s ''>
]>
<schema xmlns='http://www.w3.org/2001/XMLSchema' version='1.0'
xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'
xmlns:ds='http://www.w3.org/2000/09/xmldsig#'
targetNamespace='http://www.w3.org/2001/04/xmlenc#'
elementFormDefault='qualified'>
<import namespace='http://www.w3.org/2000/09/xmldsig#'
schemaLocation='http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd'/>
<complexType name='EncryptedType' abstract='true'>
<sequence>
<element name='EncryptionMethod' type='xenc:EncryptionMethodType'
minOccurs='0'/>
<element ref='ds:KeyInfo' minOccurs='0'/>
<element ref='xenc:CipherData'/>
<element ref='xenc:EncryptionProperties' minOccurs='0'/>
</sequence>
<attribute name='Id' type='ID' use='optional'/>
<attribute name='Type' type='anyURI' use='optional'/>
<attribute name='MimeType' type='string' use='optional'/>
<attribute name='Encoding' type='anyURI' use='optional'/>
</complexType>
<complexType name='EncryptionMethodType' mixed='true'>
<sequence>
<element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/>
<element name='OAEPparams' minOccurs='0' type='base64Binary'/>
<any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
</sequence>
<attribute name='Algorithm' type='anyURI' use='required'/>
</complexType>
<simpleType name='KeySizeType'>
<restriction base="integer"/>
</simpleType>
<element name='CipherData' type='xenc:CipherDataType'/>
<complexType name='CipherDataType'>
<choice>
<element name='CipherValue' type='base64Binary'/>
<element ref='xenc:CipherReference'/>
</choice>
</complexType>
<element name='CipherReference' type='xenc:CipherReferenceType'/>
<complexType name='CipherReferenceType'>
<choice>
<element name='Transforms' type='xenc:TransformsType' minOccurs='0'/>
</choice>
<attribute name='URI' type='anyURI' use='required'/>
</complexType>
<complexType name='TransformsType'>
<sequence>
<element ref='ds:Transform' maxOccurs='unbounded'/>
</sequence>
</complexType>
<element name='EncryptedData' type='xenc:EncryptedDataType'/>
<complexType name='EncryptedDataType'>
<complexContent>
<extension base='xenc:EncryptedType'>
</extension>
</complexContent>
</complexType>
<!-- Children of ds:KeyInfo -->
<element name='EncryptedKey' type='xenc:EncryptedKeyType'/>
<complexType name='EncryptedKeyType'>
<complexContent>
<extension base='xenc:EncryptedType'>
<sequence>
<element ref='xenc:ReferenceList' minOccurs='0'/>
<element name='CarriedKeyName' type='string' minOccurs='0'/>
</sequence>
<attribute name='Recipient' type='string'
use='optional'/>
</extension>
</complexContent>
</complexType>
<element name="AgreementMethod" type="xenc:AgreementMethodType"/>
<complexType name="AgreementMethodType" mixed="true">
<sequence>
<element name="KA-Nonce" minOccurs="0" type="base64Binary"/>
<!-- <element ref="ds:DigestMethod" minOccurs="0"/> -->
<any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
<element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/>
<element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/>
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<!-- End Children of ds:KeyInfo -->
<element name='ReferenceList'>
<complexType>
<choice minOccurs='1' maxOccurs='unbounded'>
<element name='DataReference' type='xenc:ReferenceType'/>
<element name='KeyReference' type='xenc:ReferenceType'/>
</choice>
</complexType>
</element>
<complexType name='ReferenceType'>
<sequence>
<any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
</sequence>
<attribute name='URI' type='anyURI' use='required'/>
</complexType>
<element name='EncryptionProperties' type='xenc:EncryptionPropertiesType'/>
<complexType name='EncryptionPropertiesType'>
<sequence>
<element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/>
</sequence>
<attribute name='Id' type='ID' use='optional'/>
</complexType>
<element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/>
<complexType name='EncryptionPropertyType' mixed='true'>
<choice maxOccurs='unbounded'>
<any namespace='##other' processContents='lax'/>
</choice>
<attribute name='Target' type='anyURI' use='optional'/>
<attribute name='Id' type='ID' use='optional'/>
<anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/>
</complexType>
</schema>

287
xml/xml.xsd Normal file
View File

@ -0,0 +1,287 @@
<?xml version='1.0'?>
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns ="http://www.w3.org/1999/xhtml"
xml:lang="en">
<xs:annotation>
<xs:documentation>
<div>
<h1>About the XML namespace</h1>
<div class="bodytext">
<p>
This schema document describes the XML namespace, in a form
suitable for import by other schema documents.
</p>
<p>
See <a href="http://www.w3.org/XML/1998/namespace.html">
http://www.w3.org/XML/1998/namespace.html</a> and
<a href="http://www.w3.org/TR/REC-xml">
http://www.w3.org/TR/REC-xml</a> for information
about this namespace.
</p>
<p>
Note that local names in this namespace are intended to be
defined only by the World Wide Web Consortium or its subgroups.
The names currently defined in this namespace are listed below.
They should not be used with conflicting semantics by any Working
Group, specification, or document instance.
</p>
<p>
See further below in this document for more information about <a
href="#usage">how to refer to this schema document from your own
XSD schema documents</a> and about <a href="#nsversioning">the
namespace-versioning policy governing this schema document</a>.
</p>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:attribute name="lang">
<xs:annotation>
<xs:documentation>
<div>
<h3>lang (as an attribute name)</h3>
<p>
denotes an attribute whose value
is a language code for the natural language of the content of
any element; its value is inherited. This name is reserved
by virtue of its definition in the XML specification.</p>
</div>
<div>
<h4>Notes</h4>
<p>
Attempting to install the relevant ISO 2- and 3-letter
codes as the enumerated possible values is probably never
going to be a realistic possibility.
</p>
<p>
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
and the IANA language subtag registry at
<a href="http://www.iana.org/assignments/language-subtag-registry">
http://www.iana.org/assignments/language-subtag-registry</a>
for further information.
</p>
<p>
The union allows for the 'un-declaration' of xml:lang with
the empty string.
</p>
</div>
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:union memberTypes="xs:language">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value=""/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="space">
<xs:annotation>
<xs:documentation>
<div>
<h3>space (as an attribute name)</h3>
<p>
denotes an attribute whose
value is a keyword indicating what whitespace processing
discipline is intended for the content of the element; its
value is inherited. This name is reserved by virtue of its
definition in the XML specification.</p>
</div>
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:NCName">
<xs:enumeration value="default"/>
<xs:enumeration value="preserve"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
<xs:documentation>
<div>
<h3>base (as an attribute name)</h3>
<p>
denotes an attribute whose value
provides a URI to be used as the base for interpreting any
relative URIs in the scope of the element on which it
appears; its value is inherited. This name is reserved
by virtue of its definition in the XML Base specification.</p>
<p>
See <a
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
for information about this attribute.
</p>
</div>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="id" type="xs:ID">
<xs:annotation>
<xs:documentation>
<div>
<h3>id (as an attribute name)</h3>
<p>
denotes an attribute whose value
should be interpreted as if declared to be of type ID.
This name is reserved by virtue of its definition in the
xml:id specification.</p>
<p>
See <a
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
for information about this attribute.
</p>
</div>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attributeGroup name="specialAttrs">
<xs:attribute ref="xml:base"/>
<xs:attribute ref="xml:lang"/>
<xs:attribute ref="xml:space"/>
<xs:attribute ref="xml:id"/>
</xs:attributeGroup>
<xs:annotation>
<xs:documentation>
<div>
<h3>Father (in any context at all)</h3>
<div class="bodytext">
<p>
denotes Jon Bosak, the chair of
the original XML Working Group. This name is reserved by
the following decision of the W3C XML Plenary and
XML Coordination groups:
</p>
<blockquote>
<p>
In appreciation for his vision, leadership and
dedication the W3C XML Plenary on this 10th day of
February, 2000, reserves for Jon Bosak in perpetuity
the XML name "xml:Father".
</p>
</blockquote>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation>
<div xml:id="usage" id="usage">
<h2><a name="usage">About this schema document</a></h2>
<div class="bodytext">
<p>
This schema defines attributes and an attribute group suitable
for use by schemas wishing to allow <code>xml:base</code>,
<code>xml:lang</code>, <code>xml:space</code> or
<code>xml:id</code> attributes on elements they define.
</p>
<p>
To enable this, such a schema must import this schema for
the XML namespace, e.g. as follows:
</p>
<pre>
&lt;schema . . .>
. . .
&lt;import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
</pre>
<p>
or
</p>
<pre>
&lt;import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
</pre>
<p>
Subsequently, qualified reference to any of the attributes or the
group defined below will have the desired effect, e.g.
</p>
<pre>
&lt;type . . .>
. . .
&lt;attributeGroup ref="xml:specialAttrs"/>
</pre>
<p>
will define a type which will schema-validate an instance element
with any of those attributes.
</p>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation>
<div id="nsversioning" xml:id="nsversioning">
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
<div class="bodytext">
<p>
In keeping with the XML Schema WG's standard versioning
policy, this schema document will persist at
<a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd</a>.
</p>
<p>
At the date of issue it can also be found at
<a href="http://www.w3.org/2001/xml.xsd">
http://www.w3.org/2001/xml.xsd</a>.
</p>
<p>
The schema document at that URI may however change in the future,
in order to remain compatible with the latest version of XML
Schema itself, or with the XML namespace itself. In other words,
if the XML Schema or XML namespaces change, the version of this
document at <a href="http://www.w3.org/2001/xml.xsd">
http://www.w3.org/2001/xml.xsd
</a>
will change accordingly; the version at
<a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd
</a>
will not change.
</p>
<p>
Previous dated (and unchanging) versions of this schema
document are at:
</p>
<ul>
<li><a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd</a></li>
<li><a href="http://www.w3.org/2007/08/xml.xsd">
http://www.w3.org/2007/08/xml.xsd</a></li>
<li><a href="http://www.w3.org/2004/10/xml.xsd">
http://www.w3.org/2004/10/xml.xsd</a></li>
<li><a href="http://www.w3.org/2001/03/xml.xsd">
http://www.w3.org/2001/03/xml.xsd</a></li>
</ul>
</div>
</div>
</xs:documentation>
</xs:annotation>
</xs:schema>

318
xml/xmldsig-core-schema.xsd Normal file
View File

@ -0,0 +1,318 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE schema
PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"
[
<!ATTLIST schema
xmlns:ds CDATA #FIXED "http://www.w3.org/2000/09/xmldsig#">
<!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>
<!ENTITY % p ''>
<!ENTITY % s ''>
]>
<!-- Schema for XML Signatures
http://www.w3.org/2000/09/xmldsig#
$Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $
Copyright 2001 The Internet Society and W3C (Massachusetts Institute
of Technology, Institut National de Recherche en Informatique et en
Automatique, Keio University). All Rights Reserved.
http://www.w3.org/Consortium/Legal/
This document is governed by the W3C Software License [1] as described
in the FAQ [2].
[1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
[2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
targetNamespace="http://www.w3.org/2000/09/xmldsig#"
version="0.1" elementFormDefault="qualified">
<!-- Basic Types Defined for Signatures -->
<simpleType name="CryptoBinary">
<restriction base="base64Binary">
</restriction>
</simpleType>
<!-- Start Signature -->
<element name="Signature" type="ds:SignatureType"/>
<complexType name="SignatureType">
<sequence>
<element ref="ds:SignedInfo"/>
<element ref="ds:SignatureValue"/>
<element ref="ds:KeyInfo" minOccurs="0"/>
<element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="SignatureValue" type="ds:SignatureValueType"/>
<complexType name="SignatureValueType">
<simpleContent>
<extension base="base64Binary">
<attribute name="Id" type="ID" use="optional"/>
</extension>
</simpleContent>
</complexType>
<!-- Start SignedInfo -->
<element name="SignedInfo" type="ds:SignedInfoType"/>
<complexType name="SignedInfoType">
<sequence>
<element ref="ds:CanonicalizationMethod"/>
<element ref="ds:SignatureMethod"/>
<element ref="ds:Reference" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/>
<complexType name="CanonicalizationMethodType" mixed="true">
<sequence>
<any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
<!-- (0,unbounded) elements from (1,1) namespace -->
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<element name="SignatureMethod" type="ds:SignatureMethodType"/>
<complexType name="SignatureMethodType" mixed="true">
<sequence>
<element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
<any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
<!-- (0,unbounded) elements from (1,1) external namespace -->
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<!-- Start Reference -->
<element name="Reference" type="ds:ReferenceType"/>
<complexType name="ReferenceType">
<sequence>
<element ref="ds:Transforms" minOccurs="0"/>
<element ref="ds:DigestMethod"/>
<element ref="ds:DigestValue"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
<attribute name="URI" type="anyURI" use="optional"/>
<attribute name="Type" type="anyURI" use="optional"/>
</complexType>
<element name="Transforms" type="ds:TransformsType"/>
<complexType name="TransformsType">
<sequence>
<element ref="ds:Transform" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="Transform" type="ds:TransformType"/>
<complexType name="TransformType" mixed="true">
<choice minOccurs="0" maxOccurs="unbounded">
<any namespace="##other" processContents="lax"/>
<!-- (1,1) elements from (0,unbounded) namespaces -->
<element name="XPath" type="string"/>
</choice>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<!-- End Reference -->
<element name="DigestMethod" type="ds:DigestMethodType"/>
<complexType name="DigestMethodType" mixed="true">
<sequence>
<any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<element name="DigestValue" type="ds:DigestValueType"/>
<simpleType name="DigestValueType">
<restriction base="base64Binary"/>
</simpleType>
<!-- End SignedInfo -->
<!-- Start KeyInfo -->
<element name="KeyInfo" type="ds:KeyInfoType"/>
<complexType name="KeyInfoType" mixed="true">
<choice maxOccurs="unbounded">
<element ref="ds:KeyName"/>
<element ref="ds:KeyValue"/>
<element ref="ds:RetrievalMethod"/>
<element ref="ds:X509Data"/>
<element ref="ds:PGPData"/>
<element ref="ds:SPKIData"/>
<element ref="ds:MgmtData"/>
<any processContents="lax" namespace="##other"/>
<!-- (1,1) elements from (0,unbounded) namespaces -->
</choice>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="KeyName" type="string"/>
<element name="MgmtData" type="string"/>
<element name="KeyValue" type="ds:KeyValueType"/>
<complexType name="KeyValueType" mixed="true">
<choice>
<element ref="ds:DSAKeyValue"/>
<element ref="ds:RSAKeyValue"/>
<any namespace="##other" processContents="lax"/>
</choice>
</complexType>
<element name="RetrievalMethod" type="ds:RetrievalMethodType"/>
<complexType name="RetrievalMethodType">
<sequence>
<element ref="ds:Transforms" minOccurs="0"/>
</sequence>
<attribute name="URI" type="anyURI"/>
<attribute name="Type" type="anyURI" use="optional"/>
</complexType>
<!-- Start X509Data -->
<element name="X509Data" type="ds:X509DataType"/>
<complexType name="X509DataType">
<sequence maxOccurs="unbounded">
<choice>
<element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
<element name="X509SKI" type="base64Binary"/>
<element name="X509SubjectName" type="string"/>
<element name="X509Certificate" type="base64Binary"/>
<element name="X509CRL" type="base64Binary"/>
<any namespace="##other" processContents="lax"/>
</choice>
</sequence>
</complexType>
<complexType name="X509IssuerSerialType">
<sequence>
<element name="X509IssuerName" type="string"/>
<element name="X509SerialNumber" type="integer"/>
</sequence>
</complexType>
<!-- End X509Data -->
<!-- Begin PGPData -->
<element name="PGPData" type="ds:PGPDataType"/>
<complexType name="PGPDataType">
<choice>
<sequence>
<element name="PGPKeyID" type="base64Binary"/>
<element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/>
<any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded"/>
</sequence>
<sequence>
<element name="PGPKeyPacket" type="base64Binary"/>
<any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded"/>
</sequence>
</choice>
</complexType>
<!-- End PGPData -->
<!-- Begin SPKIData -->
<element name="SPKIData" type="ds:SPKIDataType"/>
<complexType name="SPKIDataType">
<sequence maxOccurs="unbounded">
<element name="SPKISexp" type="base64Binary"/>
<any namespace="##other" processContents="lax" minOccurs="0"/>
</sequence>
</complexType>
<!-- End SPKIData -->
<!-- End KeyInfo -->
<!-- Start Object (Manifest, SignatureProperty) -->
<element name="Object" type="ds:ObjectType"/>
<complexType name="ObjectType" mixed="true">
<sequence minOccurs="0" maxOccurs="unbounded">
<any namespace="##any" processContents="lax"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
<attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
<attribute name="Encoding" type="anyURI" use="optional"/>
</complexType>
<element name="Manifest" type="ds:ManifestType"/>
<complexType name="ManifestType">
<sequence>
<element ref="ds:Reference" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="SignatureProperties" type="ds:SignaturePropertiesType"/>
<complexType name="SignaturePropertiesType">
<sequence>
<element ref="ds:SignatureProperty" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="SignatureProperty" type="ds:SignaturePropertyType"/>
<complexType name="SignaturePropertyType" mixed="true">
<choice maxOccurs="unbounded">
<any namespace="##other" processContents="lax"/>
<!-- (1,1) elements from (1,unbounded) namespaces -->
</choice>
<attribute name="Target" type="anyURI" use="required"/>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<!-- End Object (Manifest, SignatureProperty) -->
<!-- Start Algorithm Parameters -->
<simpleType name="HMACOutputLengthType">
<restriction base="integer"/>
</simpleType>
<!-- Start KeyValue Element-types -->
<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
<complexType name="DSAKeyValueType">
<sequence>
<sequence minOccurs="0">
<element name="P" type="ds:CryptoBinary"/>
<element name="Q" type="ds:CryptoBinary"/>
</sequence>
<element name="G" type="ds:CryptoBinary" minOccurs="0"/>
<element name="Y" type="ds:CryptoBinary"/>
<element name="J" type="ds:CryptoBinary" minOccurs="0"/>
<sequence minOccurs="0">
<element name="Seed" type="ds:CryptoBinary"/>
<element name="PgenCounter" type="ds:CryptoBinary"/>
</sequence>
</sequence>
</complexType>
<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
<complexType name="RSAKeyValueType">
<sequence>
<element name="Modulus" type="ds:CryptoBinary"/>
<element name="Exponent" type="ds:CryptoBinary"/>
</sequence>
</complexType>
<!-- End KeyValue Element-types -->
<!-- End Signature -->
</schema>