Compare commits

...

41 Commits

Author SHA1 Message Date
0b7ebf0e07 release: 2021.5.1 2021-05-13 20:50:31 +02:00
ddca8ef3ca tests/integration: fix outpost tests
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 20:33:41 +02:00
709581f5a8 root: use ghcr images by default
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 20:15:29 +02:00
72e41c03f5 lifecycle: run worker as root and drop perms later to fix docker permission issues
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 20:11:49 +02:00
40503d06b7 web/admin: improve UI for plex source
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 18:12:07 +02:00
1df8790050 stages/authenticator_static: fix error when listing devices
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 18:09:55 +02:00
3c23ad340f web/admin: improve diagram api for flows
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 18:01:40 +02:00
f9f2e00913 core: improve error handling for backups
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 17:56:49 +02:00
8362507bdf outposts: fix GIT_BUILD_HASH not being set correctly
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 17:49:11 +02:00
a2181c3bf0 build(deps): bump actions/create-release from 1.0.0 to 1.1.4 (#876) 2021-05-13 15:40:05 +02:00
a07ded0dae build(deps): bump actions/github-script from 0.2.0 to 4.0.2 (#877) 2021-05-13 15:39:48 +02:00
3b0b9301ee build(deps): bump django from 3.2.2 to 3.2.3 (#878) 2021-05-13 15:39:40 +02:00
919f293fc7 tests/e2e: fix redirect_uri
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 13:09:30 +02:00
c4df2e5a50 Merge branch 'master' into next
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	Pipfile.lock
2021-05-13 12:47:55 +02:00
4d1500e0f3 outposts/proxy: revert to using request Host for redirect URI
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-13 12:34:53 +02:00
281bd4c69a build(deps): bump @babel/core from 7.14.0 to 7.14.2 in /web (#868)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.14.0 to 7.14.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.2/packages/babel-core)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 11:23:08 +02:00
e4678aa032 build(deps): bump @babel/plugin-transform-runtime in /web (#869)
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.13.15 to 7.14.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.2/packages/babel-plugin-transform-runtime)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 11:21:52 +02:00
ff1c4d555a build(deps): bump @babel/preset-env from 7.14.1 to 7.14.2 in /web (#870)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.14.1 to 7.14.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.2/packages/babel-preset-env)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 11:20:46 +02:00
4a3e34d40a build(deps): bump @docusaurus/preset-classic in /website (#872)
Bumps [@docusaurus/preset-classic](https://github.com/facebook/docusaurus/tree/HEAD/packages/docusaurus-preset-classic) from 2.0.0-alpha.75 to 2.0.0-beta.0.
- [Release notes](https://github.com/facebook/docusaurus/releases)
- [Changelog](https://github.com/facebook/docusaurus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/docusaurus/commits/v2.0.0-beta.0/packages/docusaurus-preset-classic)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 11:18:39 +02:00
6939898bbe build(deps): bump @babel/plugin-proposal-decorators in /web (#871)
Bumps [@babel/plugin-proposal-decorators](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-proposal-decorators) from 7.13.15 to 7.14.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.2/packages/babel-plugin-proposal-decorators)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 11:18:30 +02:00
549607c5ed build(deps): bump kubernetes from 12.0.1 to 17.17.0 (#874)
Bumps [kubernetes](https://github.com/kubernetes-client/python) from 12.0.1 to 17.17.0.
- [Release notes](https://github.com/kubernetes-client/python/releases)
- [Changelog](https://github.com/kubernetes-client/python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes-client/python/compare/v12.0.1...v17.17.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 11:18:20 +02:00
f61acdfbfd build(deps): bump geoip2 from 4.1.0 to 4.2.0 (#873) 2021-05-13 11:15:25 +02:00
e3572bad76 build(deps): bump boto3 from 1.17.71 to 1.17.72 (#875) 2021-05-13 10:36:43 +02:00
8f99891a9d release: 2021.5.1-rc10 2021-05-12 21:25:18 +02:00
99d5262d41 ci: install git in final test containers
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 21:24:35 +02:00
97a3c2d88b release: 2021.5.1-rc9 2021-05-12 20:50:29 +02:00
e91ff4566d Merge branch 'next' into version-2021.5
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	outpost/pkg/version.go
2021-05-12 20:49:58 +02:00
dc942b2f4c outposts: build as gh-<commit hash>
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 20:37:55 +02:00
a3fccbdaff outposts: add build_hash for docker image
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 20:36:18 +02:00
bdf9f26d07 outposts: compare build hash in outdated check
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 19:05:29 +02:00
901cea1453 outposts: send build hash as part of hello
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 19:02:04 +02:00
37b57ac28f outposts: include git commit hash in build from git branch
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 18:56:44 +02:00
e9aa37ba67 outposts/ldap: fix user info caching, fix mixed case DN
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#864
2021-05-12 18:49:15 +02:00
9a0aa4c79b outposts/ldap: add infinite loop prevention
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 18:31:44 +02:00
34ab68a169 outposts: cleanup logging
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 18:01:46 +02:00
52cf4890cf root: remove servername from backup files
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 17:53:23 +02:00
8e5d03cb86 outposts: remove legacy API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 16:41:54 +02:00
2190fa555b events/api: fix error when updating transports
closes #866

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 16:41:30 +02:00
ae1edde17b ci: install git in container for dbbackup
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-05-12 16:30:51 +02:00
3ad1c3f212 web/admin: fix AuthenticatorValidationStage's form not setting notConfiguredAction
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#802
2021-05-12 16:28:14 +02:00
65ec444e52 build(deps): bump boto3 from 1.17.70 to 1.17.71 (#865)
Bumps [boto3](https://github.com/boto/boto3) from 1.17.70 to 1.17.71.
- [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.17.70...1.17.71)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-12 10:46:06 +02:00
54 changed files with 5565 additions and 4493 deletions

View File

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

View File

@ -36,9 +36,9 @@ jobs:
with: with:
push: ${{ github.event_name == 'release' }} push: ${{ github.event_name == 'release' }}
tags: | tags: |
beryju/authentik:2021.5.1-rc8, beryju/authentik:2021.5.1,
beryju/authentik:latest, beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.5.1-rc8, ghcr.io/goauthentik/server:2021.5.1,
ghcr.io/goauthentik/server:latest ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
context: . context: .
@ -75,9 +75,9 @@ jobs:
with: with:
push: ${{ github.event_name == 'release' }} push: ${{ github.event_name == 'release' }}
tags: | tags: |
beryju/authentik-proxy:2021.5.1-rc8, beryju/authentik-proxy:2021.5.1,
beryju/authentik-proxy:latest, beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.5.1-rc8, ghcr.io/goauthentik/proxy:2021.5.1,
ghcr.io/goauthentik/proxy:latest ghcr.io/goauthentik/proxy:latest
context: outpost/ context: outpost/
file: outpost/proxy.Dockerfile file: outpost/proxy.Dockerfile
@ -115,9 +115,9 @@ jobs:
with: with:
push: ${{ github.event_name == 'release' }} push: ${{ github.event_name == 'release' }}
tags: | tags: |
beryju/authentik-ldap:2021.5.1-rc8, beryju/authentik-ldap:2021.5.1,
beryju/authentik-ldap:latest, beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.5.1-rc8, ghcr.io/goauthentik/ldap:2021.5.1,
ghcr.io/goauthentik/ldap:latest ghcr.io/goauthentik/ldap:latest
context: outpost/ context: outpost/
file: outpost/ldap.Dockerfile file: outpost/ldap.Dockerfile
@ -139,7 +139,7 @@ jobs:
docker-compose pull -q docker-compose pull -q
docker-compose up --no-start docker-compose up --no-start
docker-compose start postgresql redis docker-compose start postgresql redis
docker-compose run -u root --entrypoint /bin/bash server -c "pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik" docker-compose run -u root --entrypoint /bin/bash server -c "apt-get update && apt-get install -y --no-install-recommends git && pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik"
sentry-release: sentry-release:
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
needs: needs:
@ -155,5 +155,5 @@ jobs:
SENTRY_PROJECT: authentik SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org SENTRY_URL: https://sentry.beryju.org
with: with:
version: authentik@2021.5.1-rc8 version: authentik@2021.5.1
environment: beryjuorg-prod environment: beryjuorg-prod

View File

@ -27,17 +27,17 @@ jobs:
-f Dockerfile . -f Dockerfile .
docker-compose up --no-start docker-compose up --no-start
docker-compose start postgresql redis docker-compose start postgresql redis
docker-compose run -u root --entrypoint /bin/bash server -c "pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik" docker-compose run -u root --entrypoint /bin/bash server -c "apt-get update && apt-get install -y --no-install-recommends git && pip install --no-cache -r requirements-dev.txt && ./manage.py test authentik"
- name: Extract version number - name: Extract version number
id: get_version id: get_version
uses: actions/github-script@0.2.0 uses: actions/github-script@v4.0.2
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
script: | script: |
return context.payload.ref.replace(/\/refs\/tags\/version\//, ''); return context.payload.ref.replace(/\/refs\/tags\/version\//, '');
- name: Create Release - name: Create Release
id: create_release id: create_release
uses: actions/create-release@v1.0.0 uses: actions/create-release@v1.1.4
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:

View File

@ -48,7 +48,7 @@ ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates gnupg git && \ apt-get install -y --no-install-recommends curl ca-certificates gnupg git runit && \
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
apt-get update && \ apt-get update && \
@ -58,14 +58,7 @@ RUN apt-get update && \
apt-get autoremove --purge -y && \ apt-get autoremove --purge -y && \
apt-get clean && \ apt-get clean && \
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/ && \ rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/ && \
# This is quite hacky, but docker has no guaranteed Group ID
# we could instead check for the GID of the socket and add the user dynamically,
# but then we have to drop permmissions later
groupadd -g 998 docker_998 && \
groupadd -g 999 docker_999 && \
adduser --system --no-create-home --uid 1000 --group --home /authentik authentik && \ adduser --system --no-create-home --uid 1000 --group --home /authentik authentik && \
usermod -a -G docker_998 authentik && \
usermod -a -G docker_999 authentik && \
mkdir /backups && \ mkdir /backups && \
chown authentik:authentik /backups chown authentik:authentik /backups
@ -77,7 +70,6 @@ COPY ./lifecycle/ /lifecycle
COPY --from=builder /work/authentik /authentik-proxy COPY --from=builder /work/authentik /authentik-proxy
USER authentik USER authentik
STOPSIGNAL SIGINT
ENV TMPDIR /dev/shm/ ENV TMPDIR /dev/shm/
ENV PYTHONUBUFFERED 1 ENV PYTHONUBUFFERED 1
ENTRYPOINT [ "/lifecycle/bootstrap.sh" ] ENTRYPOINT [ "/lifecycle/bootstrap.sh" ]

View File

@ -36,11 +36,5 @@ gen:
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0 --additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
cd web/api && npx tsc cd web/api && npx tsc
local-stack:
export AUTHENTIK_TAG=testing
docker build -t beryju/authentik:testng .
docker-compose up -d
docker-compose run --rm server migrate
run: run:
go run -v cmd/server/main.go go run -v cmd/server/main.go

75
Pipfile.lock generated
View File

@ -122,19 +122,18 @@
}, },
"boto3": { "boto3": {
"hashes": [ "hashes": [
"sha256:bcb1b76ca5a60586181ad202b19f4c50cb7c22ac68cae20f997abe311e22bf2a", "sha256:3317722a1e9acbfc0d30cdf273d1708c823ceb19309e9cd91cac8a3604762341",
"sha256:edf9b3b36e08cd575a9458bf59871852335aceb5db2d07bfc8530bae3a97d045" "sha256:ee3317fd79b443ef102469fac393a1ffb650ea51ac4fc27464013872c5e1ce31"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.17.71" "version": "==1.17.72"
}, },
"botocore": { "botocore": {
"hashes": [ "hashes": [
"sha256:414e1721d381095767db1cf673257fdfec639da3be9405a41d49cc859b817d68", "sha256:0fa93a2e2daad5791c63ee526ada66896cc483d04cb2d32bfcadfeb881203453"
"sha256:b7afebca1fd6ca1f8af79f377a445d474e3bd2cf88e704169d6713a6362a304f"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.20.71" "version": "==1.20.72"
}, },
"cachetools": { "cachetools": {
"hashes": [ "hashes": [
@ -323,11 +322,11 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:0a1d195ad65c52bf275b8277b3d49680bd1137a5f55039a806f25f6b9752ce3d", "sha256:13ac78dbfd189532cad8f383a27e58e18b3d33f80009ceb476d7fcbfc5dcebd8",
"sha256:18dd3145ddbd04bf189ff79b9954d08fda5171ea7b57bf705789fea766a07d50" "sha256:7e0a1393d18c16b503663752a8b6790880c5084412618990ce8a81cc908b4962"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.2.2" "version": "==3.2.3"
}, },
"django-dbbackup": { "django-dbbackup": {
"git": "https://github.com/django-dbbackup/django-dbbackup.git", "git": "https://github.com/django-dbbackup/django-dbbackup.git",
@ -441,11 +440,11 @@
}, },
"geoip2": { "geoip2": {
"hashes": [ "hashes": [
"sha256:57d8d15de2527e0697bbef44fc16812bba709f03a07ef99297bd56c1df3b1efd", "sha256:906a1dbf15a179a1af3522970e8420ab15bb3e0afc526942cc179e12146d9c1d",
"sha256:707025542ef076bd8fd80e97138bebdb7812527b2a007d141a27ad98b0370fff" "sha256:b97b44031fdc463e84eb1316b4f19edd978cb1d78703465fcb1e36dc5a822ba6"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.1.0" "version": "==4.2.0"
}, },
"google-auth": { "google-auth": {
"hashes": [ "hashes": [
@ -607,19 +606,19 @@
}, },
"kubernetes": { "kubernetes": {
"hashes": [ "hashes": [
"sha256:23c85d8571df8f56e773f1a413bc081537536dc47e2b5e8dc2e6262edb2c57ca", "sha256:225a95a0aadbd5b645ab389d941a7980db8cdad2a776fde64d1b43fc3299bde9",
"sha256:ec52ea01d52e2ec3da255992f7e859f3a76f2bdb51cf65ba8cd71dfc309d8daa" "sha256:c69b318696ba797dcf63eb928a8d4370c52319f4140023c502d7dfdf2080eb79"
], ],
"index": "pypi", "index": "pypi",
"version": "==12.0.1" "version": "==17.17.0"
}, },
"ldap3": { "ldap3": {
"hashes": [ "hashes": [
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57",
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91", "sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c", "sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056", "sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57" "sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.9" "version": "==2.9"
@ -874,37 +873,37 @@
}, },
"pyasn1": { "pyasn1": {
"hashes": [ "hashes": [
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3",
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"
], ],
"version": "==0.4.8" "version": "==0.4.8"
}, },
"pyasn1-modules": { "pyasn1-modules": {
"hashes": [ "hashes": [
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405",
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
], ],
"version": "==0.2.8" "version": "==0.2.8"
}, },
@ -1603,11 +1602,11 @@
}, },
"gitpython": { "gitpython": {
"hashes": [ "hashes": [
"sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b", "sha256:2bfcd25e6b81fe431fa3ab1f0975986cfddabf7870a323c183f3afbc9447c0c5",
"sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61" "sha256:37ac36cacf2e2be5e88f0810187c5833e71c1a2a8cf81588f5699d1b70183baa"
], ],
"markers": "python_version >= '3.4'", "markers": "python_version >= '3.5'",
"version": "==3.1.14" "version": "==3.1.16"
}, },
"idna": { "idna": {
"hashes": [ "hashes": [

View File

@ -1,3 +1,3 @@
"""authentik""" """authentik"""
__version__ = "2021.5.1-rc8" __version__ = "2021.5.1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -75,5 +75,6 @@ def backup_database(self: MonitoredTask): # pragma: no cover
Boto3Error, Boto3Error,
PermissionError, PermissionError,
CommandConnectorError, CommandConnectorError,
ValueError,
) as exc: ) as exc:
self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc)) self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc))

View File

@ -2,22 +2,25 @@
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.groups import GroupSerializer
from authentik.events.models import NotificationRule from authentik.events.models import NotificationRule
class NotificationRuleSerializer(ModelSerializer): class NotificationRuleSerializer(ModelSerializer):
"""NotificationRule Serializer""" """NotificationRule Serializer"""
group_obj = GroupSerializer(read_only=True, source="group")
class Meta: class Meta:
model = NotificationRule model = NotificationRule
depth = 2
fields = [ fields = [
"pk", "pk",
"name", "name",
"transports", "transports",
"severity", "severity",
"group", "group",
"group_obj",
] ]

View File

@ -210,6 +210,7 @@ class FlowViewSet(ModelViewSet):
request.user, "authentik_policies.view_policybinding" request.user, "authentik_policies.view_policybinding"
) )
.filter(target=stage_binding) .filter(target=stage_binding)
.exclude(policy__isnull=True)
.order_by("order") .order_by("order")
): ):
body.append( body.append(

View File

@ -42,7 +42,8 @@ outposts:
# Placeholders: # Placeholders:
# %(type)s: Outpost type; proxy, ldap, etc # %(type)s: Outpost type; proxy, ldap, etc
# %(version)s: Current version; 2021.4.1 # %(version)s: Current version; 2021.4.1
docker_image_base: "beryju/authentik-%(type)s:%(version)s" # %(build_hash)s: Build hash if you're running a beta version
docker_image_base: "ghcr.io/goauthentik/%(type)s:%(version)s"
authentik: authentik:
avatars: gravatar # gravatar or none avatars: gravatar # gravatar or none

View File

@ -4,6 +4,7 @@ from typing import Optional
from aioredis.errors import ConnectionClosedError, ReplyError from aioredis.errors import ConnectionClosedError, ReplyError
from billiard.exceptions import WorkerLostError from billiard.exceptions import WorkerLostError
from botocore.client import ClientError from botocore.client import ClientError
from botocore.exceptions import BotoCoreError
from celery.exceptions import CeleryError from celery.exceptions import CeleryError
from channels.middleware import BaseMiddleware from channels.middleware import BaseMiddleware
from channels_redis.core import ChannelFull from channels_redis.core import ChannelFull
@ -72,6 +73,7 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
WorkerLostError, WorkerLostError,
CeleryError, CeleryError,
# S3 errors # S3 errors
BotoCoreError,
ClientError, ClientError,
# custom baseclass # custom baseclass
SentryIgnoredException, SentryIgnoredException,
@ -87,6 +89,6 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
if isinstance(exc_value, ignored_classes): if isinstance(exc_value, ignored_classes):
return None return None
if "logger" in event: if "logger" in event:
if event["logger"] in ["dbbackup"]: if event["logger"] in ["dbbackup", "botocore"]:
return None return None
return event return event

View File

@ -18,8 +18,6 @@ class OutpostSerializer(ModelSerializer):
"""Outpost Serializer""" """Outpost Serializer"""
config = JSONField(validators=[is_dict], source="_config") config = JSONField(validators=[is_dict], source="_config")
# TODO: Remove _config again, this is only here for legacy with older outposts
_config = JSONField(validators=[is_dict], read_only=True)
providers_obj = ProviderSerializer(source="providers", many=True, read_only=True) providers_obj = ProviderSerializer(source="providers", many=True, read_only=True)
def validate_config(self, config) -> dict: def validate_config(self, config) -> dict:
@ -42,7 +40,6 @@ class OutpostSerializer(ModelSerializer):
"service_connection", "service_connection",
"token_identifier", "token_identifier",
"config", "config",
"_config",
] ]

View File

@ -82,6 +82,7 @@ class OutpostConsumer(AuthJsonConsumer):
) )
if msg.instruction == WebsocketMessageInstruction.HELLO: if msg.instruction == WebsocketMessageInstruction.HELLO:
state.version = msg.args.get("version", None) state.version = msg.args.get("version", None)
state.build_hash = msg.args.get("buildHash", "")
elif msg.instruction == WebsocketMessageInstruction.ACK: elif msg.instruction == WebsocketMessageInstruction.ACK:
return return
state.save(timeout=OUTPOST_HELLO_INTERVAL * 1.5) state.save(timeout=OUTPOST_HELLO_INTERVAL * 1.5)

View File

@ -1,11 +1,12 @@
"""Base Controller""" """Base Controller"""
from dataclasses import dataclass from dataclasses import dataclass
from os import environ
from typing import Optional from typing import Optional
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from structlog.testing import capture_logs from structlog.testing import capture_logs
from authentik import __version__ from authentik import ENV_GIT_HASH_KEY, __version__
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.lib.sentry import SentryIgnoredException from authentik.lib.sentry import SentryIgnoredException
from authentik.outposts.models import Outpost, OutpostServiceConnection from authentik.outposts.models import Outpost, OutpostServiceConnection
@ -69,4 +70,8 @@ class BaseController:
def get_container_image(self) -> str: def get_container_image(self) -> str:
"""Get container image to use for this outpost""" """Get container image to use for this outpost"""
image_name_template: str = CONFIG.y("outposts.docker_image_base") image_name_template: str = CONFIG.y("outposts.docker_image_base")
return image_name_template % {"type": self.outpost.type, "version": __version__} return image_name_template % {
"type": self.outpost.type,
"version": __version__,
"build_hash": environ.get(ENV_GIT_HASH_KEY, ""),
}

View File

@ -1,6 +1,7 @@
"""Outpost models""" """Outpost models"""
from dataclasses import asdict, dataclass, field from dataclasses import asdict, dataclass, field
from datetime import datetime from datetime import datetime
from os import environ
from typing import Iterable, Optional, Union from typing import Iterable, Optional, Union
from uuid import uuid4 from uuid import uuid4
@ -26,7 +27,7 @@ from packaging.version import LegacyVersion, Version, parse
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from urllib3.exceptions import HTTPError from urllib3.exceptions import HTTPError
from authentik import __version__ from authentik import ENV_GIT_HASH_KEY, __version__
from authentik.core.models import USER_ATTRIBUTE_SA, Provider, Token, TokenIntents, User from authentik.core.models import USER_ATTRIBUTE_SA, Provider, Token, TokenIntents, User
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
@ -411,6 +412,7 @@ class OutpostState:
last_seen: Optional[datetime] = field(default=None) last_seen: Optional[datetime] = field(default=None)
version: Optional[str] = field(default=None) version: Optional[str] = field(default=None)
version_should: Union[Version, LegacyVersion] = field(default=OUR_VERSION) version_should: Union[Version, LegacyVersion] = field(default=OUR_VERSION)
build_hash: str = field(default="")
_outpost: Optional[Outpost] = field(default=None) _outpost: Optional[Outpost] = field(default=None)
@ -419,6 +421,8 @@ class OutpostState:
"""Check if outpost version matches our version""" """Check if outpost version matches our version"""
if not self.version: if not self.version:
return False return False
if self.build_hash != environ.get(ENV_GIT_HASH_KEY, ""):
return False
return parse(self.version) < OUR_VERSION return parse(self.version) < OUR_VERSION
@staticmethod @staticmethod

View File

@ -320,6 +320,7 @@ CELERY_RESULT_BACKEND = (
# Database backup # Database backup
DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage" DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage"
DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"} DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"}
DBBACKUP_FILENAME_TEMPLATE = "authentik-backup-{datetime}.sql"
if CONFIG.y("postgresql.s3_backup"): if CONFIG.y("postgresql.s3_backup"):
DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
DBBACKUP_STORAGE_OPTIONS = { DBBACKUP_STORAGE_OPTIONS = {

View File

@ -1,9 +1,8 @@
"""AuthenticatorStaticStage API Views""" """AuthenticatorStaticStage API Views"""
from django_filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from django_otp.plugins.otp_static.models import StaticDevice from django_otp.plugins.otp_static.models import StaticDevice
from guardian.utils import get_anonymous_user from guardian.utils import get_anonymous_user
from rest_framework.filters import SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet

View File

@ -21,7 +21,7 @@ services:
networks: networks:
- internal - internal
server: server:
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc8} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.5.1}
restart: unless-stopped restart: unless-stopped
command: server command: server
environment: environment:
@ -52,7 +52,7 @@ services:
- "0.0.0.0:9000:9000" - "0.0.0.0:9000:9000"
- "0.0.0.0:9443:9443" - "0.0.0.0:9443:9443"
worker: worker:
image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.5.1-rc8} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.5.1}
restart: unless-stopped restart: unless-stopped
command: worker command: worker
networks: networks:
@ -64,8 +64,13 @@ services:
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
# AUTHENTIK_ERROR_REPORTING__ENABLED: "true" # AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
# This is optional, and can be removed. If you remove this, the following will happen
# - The permissions for the /backups and /media folders aren't fixed, so make sure they are 1000:1000
# - The docker socket can't be accessed anymore
user: root
volumes: volumes:
- ./backups:/backups - ./backups:/backups
- ./media:/media
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- ./custom-templates:/templates - ./custom-templates:/templates
- geoip:/geoip - geoip:/geoip

View File

@ -1,3 +1,3 @@
package constants package constants
const VERSION = "2021.5.1-rc8" const VERSION = "2021.5.1"

View File

@ -1,14 +1,29 @@
#!/bin/bash -e #!/bin/bash -e
python -m lifecycle.wait_for_db python -m lifecycle.wait_for_db
printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr
function check_if_root {
if [[ $EUID -ne 0 ]]; then
printf '{"event": "Not running as root, disabling permission fixes", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr
return
fi
SOCKET="/var/run/docker.sock"
if [[ -e "$SOCKET" ]]; then
# Get group ID of the docker socket, so we can create a matching group and
# add ourselves to it
DOCKER_GID=$(stat -c '%g' $SOCKET)
usermod -a -G $DOCKER_GID authentik
fi
# Fix permissions of backups and media
chown -R authentik:authentik /media /backups
}
if [[ "$1" == "server" ]]; then if [[ "$1" == "server" ]]; then
python -m lifecycle.migrate python -m lifecycle.migrate
/authentik-proxy /authentik-proxy
elif [[ "$1" == "worker" ]]; then elif [[ "$1" == "worker" ]]; then
celery -A authentik.root.celery worker --autoscale 3,1 -E -B -s /tmp/celerybeat-schedule -Q authentik,authentik_scheduled,authentik_events check_if_root
elif [[ "$1" == "migrate" ]]; then chpst -u authentik env HOME=/authentik celery -A authentik.root.celery worker --autoscale 3,1 -E -B -s /tmp/celerybeat-schedule -Q authentik,authentik_scheduled,authentik_events
printf "DEPERECATED: database migrations are now executed automatically on startup."
python -m lifecycle.migrate
elif [[ "$1" == "backup" ]]; then elif [[ "$1" == "backup" ]]; then
python -m manage dbbackup --clean python -m manage dbbackup --clean
elif [[ "$1" == "restore" ]]; then elif [[ "$1" == "restore" ]]; then

View File

@ -113,10 +113,21 @@ stages:
inputs: inputs:
containerRegistry: 'beryjuorg-harbor' containerRegistry: 'beryjuorg-harbor'
repository: 'authentik/outpost-proxy' repository: 'authentik/outpost-proxy'
command: 'buildAndPush' command: 'build'
Dockerfile: 'outpost/proxy.Dockerfile' Dockerfile: 'outpost/proxy.Dockerfile'
buildContext: 'outpost/' buildContext: 'outpost/'
tags: "gh-$(branchName)" tags: |
gh-$(branchName)
gh-$(Build.SourceVersion)
arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)'
- task: Docker@2
inputs:
containerRegistry: 'beryjuorg-harbor'
repository: 'authentik/outpost-proxy'
command: 'push'
tags: |
gh-$(branchName)
gh-$(Build.SourceVersion)
- job: ldap_build_docker - job: ldap_build_docker
pool: pool:
vmImage: 'ubuntu-latest' vmImage: 'ubuntu-latest'
@ -138,7 +149,18 @@ stages:
inputs: inputs:
containerRegistry: 'beryjuorg-harbor' containerRegistry: 'beryjuorg-harbor'
repository: 'authentik/outpost-ldap' repository: 'authentik/outpost-ldap'
command: 'buildAndPush' command: 'build'
Dockerfile: 'outpost/ldap.Dockerfile' Dockerfile: 'outpost/ldap.Dockerfile'
buildContext: 'outpost/' buildContext: 'outpost/'
tags: "gh-$(branchName)" tags: |
gh-$(branchName)
gh-$(Build.SourceVersion)
arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)'
- task: Docker@2
inputs:
containerRegistry: 'beryjuorg-harbor'
repository: 'authentik/outpost-ldap'
command: 'push'
tags: |
gh-$(branchName)
gh-$(Build.SourceVersion)

View File

@ -1,4 +1,6 @@
FROM golang:1.16.4 AS builder FROM golang:1.16.4 AS builder
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
WORKDIR /work WORKDIR /work

View File

@ -1,7 +1,6 @@
package ak package ak
import ( import (
"fmt"
"math/rand" "math/rand"
"net/url" "net/url"
"os" "os"
@ -43,7 +42,7 @@ type APIController struct {
// NewAPIController initialise new API Controller instance from URL and API token // NewAPIController initialise new API Controller instance from URL and API token
func NewAPIController(akURL url.URL, token string) *APIController { func NewAPIController(akURL url.URL, token string) *APIController {
transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme}) transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme})
transport.Transport = SetUserAgent(getTLSTransport(), fmt.Sprintf("authentik-proxy@%s", pkg.VERSION)) transport.Transport = SetUserAgent(getTLSTransport(), pkg.UserAgent())
// create the transport // create the transport
auth := httptransport.BearerToken(token) auth := httptransport.BearerToken(token)

View File

@ -23,7 +23,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
header := http.Header{ header := http.Header{
"Authorization": []string{authHeader}, "Authorization": []string{authHeader},
"User-Agent": []string{fmt.Sprintf("authentik-proxy@%s", pkg.VERSION)}, "User-Agent": []string{pkg.UserAgent()},
} }
value, set := os.LookupEnv("AUTHENTIK_INSECURE") value, set := os.LookupEnv("AUTHENTIK_INSECURE")
@ -46,8 +46,9 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
msg := websocketMessage{ msg := websocketMessage{
Instruction: WebsocketInstructionHello, Instruction: WebsocketInstructionHello,
Args: map[string]interface{}{ Args: map[string]interface{}{
"version": pkg.VERSION, "version": pkg.VERSION,
"uuid": ac.instanceUUID.String(), "buildHash": pkg.BUILD(),
"uuid": ac.instanceUUID.String(),
}, },
} }
err := ws.WriteJSON(msg) err := ws.WriteJSON(msg)
@ -76,7 +77,7 @@ func (ac *APIController) startWSHandler() {
var wsMsg websocketMessage var wsMsg websocketMessage
err := ac.wsConn.ReadJSON(&wsMsg) err := ac.wsConn.ReadJSON(&wsMsg)
if err != nil { if err != nil {
logger.Println("read:", err) logger.WithError(err).Warning("ws write error, reconnecting")
ac.wsConn.CloseAndReconnect() ac.wsConn.CloseAndReconnect()
continue continue
} }
@ -100,14 +101,15 @@ func (ac *APIController) startWSHealth() {
aliveMsg := websocketMessage{ aliveMsg := websocketMessage{
Instruction: WebsocketInstructionHello, Instruction: WebsocketInstructionHello,
Args: map[string]interface{}{ Args: map[string]interface{}{
"version": pkg.VERSION, "version": pkg.VERSION,
"uuid": ac.instanceUUID.String(), "buildHash": pkg.BUILD(),
"uuid": ac.instanceUUID.String(),
}, },
} }
err := ac.wsConn.WriteJSON(aliveMsg) err := ac.wsConn.WriteJSON(aliveMsg)
ac.logger.WithField("loop", "ws-health").Trace("hello'd") ac.logger.WithField("loop", "ws-health").Trace("hello'd")
if err != nil { if err != nil {
ac.logger.WithField("loop", "ws-health").Println("write:", err) ac.logger.WithField("loop", "ws-health").WithError(err).Warning("ws write error, reconnecting")
ac.wsConn.CloseAndReconnect() ac.wsConn.CloseAndReconnect()
continue continue
} }

View File

@ -33,7 +33,7 @@ func doGlobalSetup(config map[string]interface{}) {
default: default:
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
} }
log.WithField("version", pkg.VERSION).Info("Starting authentik outpost") log.WithField("buildHash", pkg.BUILD()).WithField("version", pkg.VERSION).Info("Starting authentik outpost")
var dsn string var dsn string
if config[ConfigErrorReportingEnabled].(bool) { if config[ConfigErrorReportingEnabled].(bool) {

View File

@ -2,20 +2,22 @@ package ldap
import ( import (
"net" "net"
"strings"
"github.com/nmcclain/ldap" "github.com/nmcclain/ldap"
) )
func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) { func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) {
ls.log.WithField("boundDN", bindDN).Info("bind") ls.log.WithField("bindDN", bindDN).Info("bind")
bindDN = strings.ToLower(bindDN)
for _, instance := range ls.providers { for _, instance := range ls.providers {
username, err := instance.getUsername(bindDN) username, err := instance.getUsername(bindDN)
if err == nil { if err == nil {
return instance.Bind(username, bindPW, conn) return instance.Bind(username, bindDN, bindPW, conn)
} else { } else {
ls.log.WithError(err).Debug("Username not for instance") ls.log.WithError(err).Debug("Username not for instance")
} }
} }
ls.log.WithField("boundDN", bindDN).WithField("request", "bind").Warning("No provider found for request") ls.log.WithField("bindDN", bindDN).WithField("request", "bind").Warning("No provider found for request")
return ldap.LDAPResultOperationsError, nil return ldap.LDAPResultOperationsError, nil
} }

View File

@ -47,7 +47,7 @@ func (pi *ProviderInstance) getUsername(dn string) (string, error) {
return "", errors.New("failed to find cn") return "", errors.New("failed to find cn")
} }
func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) { func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) {
jar, err := cookiejar.New(nil) jar, err := cookiejar.New(nil)
if err != nil { if err != nil {
pi.log.WithError(err).Warning("Failed to create cookiejar") pi.log.WithError(err).Warning("Failed to create cookiejar")
@ -67,9 +67,9 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn)
} }
params := url.Values{} params := url.Values{}
params.Add("goauthentik.io/outpost/ldap", "true") params.Add("goauthentik.io/outpost/ldap", "true")
passed, err := pi.solveFlowChallenge(username, bindPW, client, params.Encode()) passed, err := pi.solveFlowChallenge(username, bindPW, client, params.Encode(), 1)
if err != nil { if err != nil {
pi.log.WithField("boundDN", username).WithError(err).Warning("failed to solve challenge") pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to solve challenge")
return ldap.LDAPResultOperationsError, nil return ldap.LDAPResultOperationsError, nil
} }
if !passed { if !passed {
@ -82,25 +82,25 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn)
}, httptransport.PassThroughAuth) }, httptransport.PassThroughAuth)
if err != nil { if err != nil {
if _, denied := err.(*core.CoreApplicationsCheckAccessForbidden); denied { if _, denied := err.(*core.CoreApplicationsCheckAccessForbidden); denied {
pi.log.WithField("boundDN", username).Info("Access denied for user") pi.log.WithField("bindDN", bindDN).Info("Access denied for user")
return ldap.LDAPResultInsufficientAccessRights, nil return ldap.LDAPResultInsufficientAccessRights, nil
} }
pi.log.WithField("boundDN", username).WithError(err).Warning("failed to check access") pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to check access")
return ldap.LDAPResultOperationsError, nil return ldap.LDAPResultOperationsError, nil
} }
pi.log.WithField("boundDN", username).Info("User has access") pi.log.WithField("bindDN", bindDN).Info("User has access")
// Get user info to store in context // Get user info to store in context
userInfo, err := pi.s.ac.Client.Core.CoreUsersMe(&core.CoreUsersMeParams{ userInfo, err := pi.s.ac.Client.Core.CoreUsersMe(&core.CoreUsersMeParams{
Context: context.Background(), Context: context.Background(),
HTTPClient: client, HTTPClient: client,
}, httptransport.PassThroughAuth) }, httptransport.PassThroughAuth)
if err != nil { if err != nil {
pi.log.WithField("boundDN", username).WithError(err).Warning("failed to get user info") pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to get user info")
return ldap.LDAPResultOperationsError, nil return ldap.LDAPResultOperationsError, nil
} }
pi.boundUsersMutex.Lock() pi.boundUsersMutex.Lock()
pi.boundUsers[username] = UserFlags{ pi.boundUsers[bindDN] = UserFlags{
UserInfo: userInfo.Payload.User, UserInfo: *userInfo.Payload.User,
CanSearch: pi.SearchAccessCheck(userInfo.Payload.User), CanSearch: pi.SearchAccessCheck(userInfo.Payload.User),
} }
defer pi.boundUsersMutex.Unlock() defer pi.boundUsersMutex.Unlock()
@ -112,7 +112,8 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn)
func (pi *ProviderInstance) SearchAccessCheck(user *models.User) bool { func (pi *ProviderInstance) SearchAccessCheck(user *models.User) bool {
for _, group := range user.Groups { for _, group := range user.Groups {
for _, allowedGroup := range pi.searchAllowedGroups { for _, allowedGroup := range pi.searchAllowedGroups {
if &group.Pk == allowedGroup { pi.log.WithField("userGroup", group.Pk).WithField("allowedGroup", allowedGroup).Trace("Checking search access")
if group.Pk.String() == allowedGroup.String() {
pi.log.WithField("group", group.Name).Info("Allowed access to search") pi.log.WithField("group", group.Name).Info("Allowed access to search")
return true return true
} }
@ -139,7 +140,7 @@ func (pi *ProviderInstance) delayDeleteUserInfo(dn string) {
}() }()
} }
func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *http.Client, urlParams string) (bool, error) { func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *http.Client, urlParams string, depth int) (bool, error) {
challenge, err := pi.s.ac.Client.Flows.FlowsExecutorGet(&flows.FlowsExecutorGetParams{ challenge, err := pi.s.ac.Client.Flows.FlowsExecutorGet(&flows.FlowsExecutorGetParams{
FlowSlug: pi.flowSlug, FlowSlug: pi.flowSlug,
Query: urlParams, Query: urlParams,
@ -169,6 +170,10 @@ func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, c
} }
response, err := pi.s.ac.Client.Flows.FlowsExecutorSolve(responseParams, pi.s.ac.Auth) response, err := pi.s.ac.Client.Flows.FlowsExecutorSolve(responseParams, pi.s.ac.Auth)
pi.log.WithField("component", response.Payload.Component).WithField("type", *response.Payload.Type).Debug("Got response") pi.log.WithField("component", response.Payload.Component).WithField("type", *response.Payload.Type).Debug("Got response")
switch response.Payload.Component {
case "ak-stage-access-denied":
return false, errors.New("got ak-stage-access-denied")
}
if *response.Payload.Type == "redirect" { if *response.Payload.Type == "redirect" {
return true, nil return true, nil
} }
@ -184,5 +189,8 @@ func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, c
} }
} }
} }
return pi.solveFlowChallenge(bindDN, password, client, urlParams) if depth >= 10 {
return false, errors.New("exceeded stage recursion depth")
}
return pi.solveFlowChallenge(bindDN, password, client, urlParams, depth+1)
} }

View File

@ -29,10 +29,13 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest,
pi.boundUsersMutex.RLock() pi.boundUsersMutex.RLock()
defer pi.boundUsersMutex.RUnlock() defer pi.boundUsersMutex.RUnlock()
flags, ok := pi.boundUsers[bindDN] flags, ok := pi.boundUsers[bindDN]
pi.log.WithField("bindDN", bindDN).WithField("ok", ok).Debugf("%+v\n", flags)
if !ok { if !ok {
pi.log.Debug("User info not cached")
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied")
} }
if !flags.CanSearch { if !flags.CanSearch {
pi.log.Debug("User can't search")
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied")
} }

View File

@ -31,7 +31,7 @@ type ProviderInstance struct {
} }
type UserFlags struct { type UserFlags struct {
UserInfo *models.User UserInfo models.User
CanSearch bool CanSearch bool
} }

View File

@ -8,8 +8,8 @@ import (
"github.com/nmcclain/ldap" "github.com/nmcclain/ldap"
) )
func (ls *LDAPServer) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) {
ls.log.WithField("boundDN", boundDN).WithField("baseDN", searchReq.BaseDN).Info("search") ls.log.WithField("bindDN", bindDN).WithField("baseDN", searchReq.BaseDN).Info("search")
if searchReq.BaseDN == "" { if searchReq.BaseDN == "" {
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultSuccess}, nil return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultSuccess}, nil
} }
@ -21,7 +21,7 @@ func (ls *LDAPServer) Search(boundDN string, searchReq ldap.SearchRequest, conn
for _, provider := range ls.providers { for _, provider := range ls.providers {
providerBase, _ := goldap.ParseDN(provider.BaseDN) providerBase, _ := goldap.ParseDN(provider.BaseDN)
if providerBase.AncestorOf(bd) { if providerBase.AncestorOf(bd) {
return provider.Search(boundDN, searchReq, conn) return provider.Search(bindDN, searchReq, conn)
} }
} }
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, errors.New("no provider could handle request") return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, errors.New("no provider could handle request")

View File

@ -161,7 +161,7 @@ func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) {
p.ErrorPage(rw, http.StatusInternalServerError, "Internal Server Error", err.Error()) p.ErrorPage(rw, http.StatusInternalServerError, "Internal Server Error", err.Error())
return return
} }
redirectURI := p.GetRedirectURI(getHost(req)) redirectURI := p.GetRedirectURI(req.Host)
http.Redirect(rw, req, p.provider.GetLoginURL(redirectURI, fmt.Sprintf("%v:%v", nonce, redirect)), http.StatusFound) http.Redirect(rw, req, p.provider.GetLoginURL(redirectURI, fmt.Sprintf("%v:%v", nonce, redirect)), http.StatusFound)
} }

View File

@ -1,3 +1,16 @@
package pkg package pkg
const VERSION = "2021.5.1-rc8" import (
"fmt"
"os"
)
const VERSION = "2021.5.1"
func BUILD() string {
return os.Getenv("GIT_BUILD_HASH")
}
func UserAgent() string {
return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD())
}

View File

@ -1,4 +1,6 @@
FROM golang:1.16.4 AS builder FROM golang:1.16.4 AS builder
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
WORKDIR /work WORKDIR /work

View File

@ -15694,6 +15694,7 @@ definitions:
NotificationRule: NotificationRule:
required: required:
- name - name
- transports
type: object type: object
properties: properties:
pk: pk:
@ -15706,38 +15707,17 @@ definitions:
type: string type: string
minLength: 1 minLength: 1
transports: transports:
description: Select which transports should be used to notify the user. If
none are selected, the notification will only be shown in the authentik
UI.
type: array type: array
items: items:
required: description: Select which transports should be used to notify the user.
- name If none are selected, the notification will only be shown in the authentik
- mode UI.
type: object type: string
properties: format: uuid
uuid: uniqueItems: true
title: Uuid
type: string
format: uuid
readOnly: true
name:
title: Name
type: string
minLength: 1
mode:
title: Mode
type: string
enum:
- webhook
- webhook_slack
- email
webhook_url:
title: Webhook url
type: string
send_once:
title: Send once
description: Only send notification once, for example when sending a
webhook into a chat channel.
type: boolean
readOnly: true
severity: severity:
title: Severity title: Severity
description: Controls which severity level the created notifications will description: Controls which severity level the created notifications will
@ -15748,57 +15728,14 @@ definitions:
- warning - warning
- alert - alert
group: group:
required: title: Group
- name description: Define which group of users this notification should be sent
type: object and shown to. If left empty, Notification won't ben sent.
properties: type: string
group_uuid: format: uuid
title: Group uuid x-nullable: true
type: string group_obj:
format: uuid $ref: '#/definitions/Group'
readOnly: true
name:
title: Name
type: string
maxLength: 80
minLength: 1
is_superuser:
title: Is superuser
description: Users added to this group will be superusers.
type: boolean
attributes:
title: Attributes
type: object
parent:
required:
- name
- parent
type: object
properties:
group_uuid:
title: Group uuid
type: string
format: uuid
readOnly: true
name:
title: Name
type: string
maxLength: 80
minLength: 1
is_superuser:
title: Is superuser
description: Users added to this group will be superusers.
type: boolean
attributes:
title: Attributes
type: object
parent:
title: Parent
type: string
format: uuid
x-nullable: true
readOnly: true
readOnly: true
NotificationTransport: NotificationTransport:
required: required:
- name - name

View File

@ -70,7 +70,7 @@ class TestProviderProxy(SeleniumTestCase):
authorization_flow=Flow.objects.get( authorization_flow=Flow.objects.get(
slug="default-provider-authorization-implicit-consent" slug="default-provider-authorization-implicit-consent"
), ),
internal_host="http://localhost:80", internal_host="http://localhost",
external_host="http://localhost:4180", external_host="http://localhost:4180",
) )
# Ensure OAuth2 Params are set # Ensure OAuth2 Params are set
@ -123,7 +123,7 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase):
authorization_flow=Flow.objects.get( authorization_flow=Flow.objects.get(
slug="default-provider-authorization-implicit-consent" slug="default-provider-authorization-implicit-consent"
), ),
internal_host="http://localhost:80", internal_host="http://localhost",
external_host="http://localhost:4180", external_host="http://localhost:4180",
) )
# Ensure OAuth2 Params are set # Ensure OAuth2 Params are set

View File

@ -104,5 +104,5 @@ class OutpostDockerTests(TestCase):
self.assertEqual(compose["version"], "3.5") self.assertEqual(compose["version"], "3.5")
self.assertEqual( self.assertEqual(
compose["services"]["authentik_proxy"]["image"], compose["services"]["authentik_proxy"]["image"],
f"beryju/authentik-proxy:{__version__}", f"ghcr.io/goauthentik/proxy:{__version__}",
) )

View File

@ -104,5 +104,5 @@ class TestProxyDocker(TestCase):
self.assertEqual(compose["version"], "3.5") self.assertEqual(compose["version"], "3.5")
self.assertEqual( self.assertEqual(
compose["services"]["authentik_proxy"]["image"], compose["services"]["authentik_proxy"]["image"],
f"beryju/authentik-proxy:{__version__}", f"ghcr.io/goauthentik/proxy:{__version__}",
) )

View File

@ -81,7 +81,7 @@ http {
location /static/ { location /static/ {
expires 31d; expires 31d;
add_header Cache-Control "public, no-transform"; add_header Cache-Control "public, no-transform";
add_header X-authentik-version "2021.5.1-rc8"; add_header X-authentik-version "2021.5.1";
add_header Vary X-authentik-version; add_header Vary X-authentik-version;
} }

1379
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -35,10 +35,10 @@
] ]
}, },
"dependencies": { "dependencies": {
"@babel/core": "^7.14.0", "@babel/core": "^7.14.2",
"@babel/plugin-proposal-decorators": "^7.13.15", "@babel/plugin-proposal-decorators": "^7.14.2",
"@babel/plugin-transform-runtime": "^7.13.15", "@babel/plugin-transform-runtime": "^7.14.2",
"@babel/preset-env": "^7.14.1", "@babel/preset-env": "^7.14.2",
"@babel/preset-typescript": "^7.13.0", "@babel/preset-typescript": "^7.13.0",
"@fortawesome/fontawesome-free": "^5.15.3", "@fortawesome/fontawesome-free": "^5.15.3",
"@lingui/cli": "^3.8.10", "@lingui/cli": "^3.8.10",

View File

@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger"; export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress"; export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current"; export const CURRENT_CLASS = "pf-m-current";
export const VERSION = "2021.5.1-rc8"; export const VERSION = "2021.5.1";
export const PAGE_SIZE = 20; export const PAGE_SIZE = 20;
export const EVENT_REFRESH = "ak-refresh"; export const EVENT_REFRESH = "ak-refresh";
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle"; export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";

View File

@ -67,7 +67,7 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
<option value="" ?selected=${this.instance?.group === undefined}>---------</option> <option value="" ?selected=${this.instance?.group === undefined}>---------</option>
${until(new CoreApi(DEFAULT_CONFIG).coreGroupsList({}).then(groups => { ${until(new CoreApi(DEFAULT_CONFIG).coreGroupsList({}).then(groups => {
return groups.results.map(group => { return groups.results.map(group => {
return html`<option value=${ifDefined(group.pk)} ?selected=${this.instance?.group?.groupUuid === group.pk}>${group.name}</option>`; return html`<option value=${ifDefined(group.pk)} ?selected=${this.instance?.group === group.pk}>${group.name}</option>`;
}); });
}), html`<option>${t`Loading...`}</option>`)} }), html`<option>${t`Loading...`}</option>`)}
</select> </select>
@ -80,7 +80,7 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
${until(new EventsApi(DEFAULT_CONFIG).eventsTransportsList({}).then(transports => { ${until(new EventsApi(DEFAULT_CONFIG).eventsTransportsList({}).then(transports => {
return transports.results.map(transport => { return transports.results.map(transport => {
const selected = Array.from(this.instance?.transports || []).some(su => { const selected = Array.from(this.instance?.transports || []).some(su => {
return su.uuid == transport.pk; return su == transport.pk;
}); });
return html`<option value=${ifDefined(transport.pk)} ?selected=${selected}>${transport.name}</option>`; return html`<option value=${ifDefined(transport.pk)} ?selected=${selected}>${transport.name}</option>`;
}); });

View File

@ -55,7 +55,7 @@ export class RuleListPage extends TablePage<NotificationRule> {
return [ return [
html`${item.name}`, html`${item.name}`,
html`${item.severity}`, html`${item.severity}`,
html`${item.group?.name || t`None (rule disabled)`}`, html`${item.groupObj?.name || t`None (rule disabled)`}`,
html` html`
<ak-forms-modal> <ak-forms-modal>
<span slot="submit"> <span slot="submit">

View File

@ -58,14 +58,6 @@ export class FlowViewPage extends LitElement {
<ak-tabs> <ak-tabs>
<div slot="page-overview" data-tab-title="${t`Flow Overview`}" class="pf-c-page__main-section pf-m-no-padding-mobile"> <div slot="page-overview" data-tab-title="${t`Flow Overview`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-l-gallery pf-m-gutter"> <div class="pf-l-gallery pf-m-gutter">
<div class="pf-c-card pf-l-gallery__item" style="grid-column-end: span 4;grid-row-end: span 2;">
<div class="pf-c-card">
<div class="pf-c-card__body">
<ak-flow-diagram flowSlug=${this.flow.slug}>
</ak-flow-diagram>
</div>
</div>
</div>
<div class="pf-c-card pf-l-gallery__item"> <div class="pf-c-card pf-l-gallery__item">
<div class="pf-c-card__title">${t`Related`}</div> <div class="pf-c-card__title">${t`Related`}</div>
<div class="pf-c-card__body"> <div class="pf-c-card__body">
@ -94,6 +86,14 @@ export class FlowViewPage extends LitElement {
</dl> </dl>
</div> </div>
</div> </div>
<div class="pf-c-card pf-l-gallery__item" style="grid-column-end: span 4;grid-row-end: span 2;">
<div class="pf-c-card">
<div class="pf-c-card__body">
<ak-flow-diagram flowSlug=${this.flow.slug}>
</ak-flow-diagram>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div slot="page-stage-bindings" data-tab-title="${t`Stage Bindings`}" class="pf-c-page__main-section pf-m-no-padding-mobile"> <div slot="page-stage-bindings" data-tab-title="${t`Stage Bindings`}" class="pf-c-page__main-section pf-m-no-padding-mobile">

View File

@ -42,13 +42,12 @@ export class OutpostHealthElement extends LitElement {
return html`<ak-spinner></ak-spinner>`; return html`<ak-spinner></ak-spinner>`;
} }
if (this.outpostHealth.length === 0) { if (this.outpostHealth.length === 0) {
return html`<li> return html`
<ul> <ul>
<li role="cell"> <li role="cell">
<ak-label color=${PFColor.Grey} text=${t`Not available`}></ak-label> <ak-label color=${PFColor.Grey} text=${t`Not available`}></ak-label>
</li> </li>
</ul> </ul>`;
</li>`;
} }
return html`<ul>${this.outpostHealth.map((h) => { return html`<ul>${this.outpostHealth.map((h) => {
return html`<li> return html`<li>

View File

@ -76,6 +76,40 @@ export class PlexSourceForm extends ModelForm<PlexSource, string> {
this.plexResources = await new PlexAPIClient(this.plexToken).getServers(); this.plexResources = await new PlexAPIClient(this.plexToken).getServers();
} }
renderSettings(): TemplateResult {
if (!this.plexToken) {
return html`
<button class="pf-c-button pf-m-primary" type="button" @click=${() => {
this.doAuth();
}}>
${t`Load servers`}
</button>`;
}
return html`<ak-form-element-horizontal name="allowFriends">
<div class="pf-c-check">
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.allowFriends, true)}>
<label class="pf-c-check__label">
${t`Allow friends to authenticate via Plex, even if you don't share any servers`}
</label>
</div>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Allowed servers`}
?required=${true}
name="allowedServers">
<select class="pf-c-form-control" multiple>
${this.plexResources?.map(r => {
const selected = Array.from(this.instance?.allowedServers || []).some(server => {
return server == r.clientIdentifier;
});
return html`<option value=${r.clientIdentifier} ?selected=${selected}>${r.name}</option>`;
})}
</select>
<p class="pf-c-form__helper-text">${t`Select which server a user has to be a member of to be allowed to authenticate.`}</p>
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
</ak-form-element-horizontal>`;
}
renderForm(): TemplateResult { renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal"> return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal <ak-form-element-horizontal
@ -132,36 +166,7 @@ export class PlexSourceForm extends ModelForm<PlexSource, string> {
name="clientId"> name="clientId">
<input type="text" value="${first(this.instance?.clientId)}" class="pf-c-form-control" required> <input type="text" value="${first(this.instance?.clientId)}" class="pf-c-form-control" required>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal name="allowFriends"> ${this.renderSettings()}
<div class="pf-c-check">
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.allowFriends, true)}>
<label class="pf-c-check__label">
${t`Allow friends to authenticate via Plex, even if you don't share any servers`}
</label>
</div>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Allowed servers`}
?required=${true}
name="allowedServers">
<select class="pf-c-form-control" multiple>
${this.plexResources?.map(r => {
const selected = Array.from(this.instance?.allowedServers || []).some(server => {
return server == r.clientIdentifier;
});
return html`<option value=${r.clientIdentifier} ?selected=${selected}>${r.name}</option>`;
})}
</select>
<p class="pf-c-form__helper-text">${t`Select which server a user has to be a member of to be allowed to authenticate.`}</p>
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
<p class="pf-c-form__helper-text">
<button class="pf-c-button pf-m-primary" type="button" @click=${() => {
this.doAuth();
}}>
${t`Load servers`}
</button>
</p>
</ak-form-element-horizontal>
</div> </div>
</ak-form-group> </ak-form-group>
<ak-form-group> <ak-form-group>

View File

@ -70,7 +70,7 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
<ak-form-element-horizontal <ak-form-element-horizontal
label=${t`Not configured action`} label=${t`Not configured action`}
?required=${true} ?required=${true}
name="mode"> name="notConfiguredAction">
<select class="pf-c-form-control" @change=${(ev: Event) => { <select class="pf-c-form-control" @change=${(ev: Event) => {
const target = ev.target as HTMLSelectElement; const target = ev.target as HTMLSelectElement;
if (target.selectedOptions[0].value === AuthenticatorValidateStageNotConfiguredActionEnum.Configure) { if (target.selectedOptions[0].value === AuthenticatorValidateStageNotConfiguredActionEnum.Configure) {

View File

@ -16,7 +16,7 @@ Download the latest `docker-compose.yml` from [here](https://raw.githubuserconte
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env` To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.5.1-rc8 >> .env` To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.5.1 >> .env`
If this is a fresh authentik install run the following commands to generate a password: If this is a fresh authentik install run the following commands to generate a password:

View File

@ -11,7 +11,7 @@ version: "3.5"
services: services:
authentik_proxy: authentik_proxy:
image: beryju/authentik-proxy:2021.5.1-rc8 image: beryju/authentik-proxy:2021.5.1
ports: ports:
- 4180:4180 - 4180:4180
- 4443:4443 - 4443:4443

View File

@ -14,7 +14,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.5.1-rc8 app.kubernetes.io/version: 2021.5.1
name: authentik-outpost-api name: authentik-outpost-api
stringData: stringData:
authentik_host: "__AUTHENTIK_URL__" authentik_host: "__AUTHENTIK_URL__"
@ -29,7 +29,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.5.1-rc8 app.kubernetes.io/version: 2021.5.1
name: authentik-outpost name: authentik-outpost
spec: spec:
ports: ports:
@ -54,7 +54,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.5.1-rc8 app.kubernetes.io/version: 2021.5.1
name: authentik-outpost name: authentik-outpost
spec: spec:
selector: selector:
@ -62,14 +62,14 @@ spec:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.5.1-rc8 app.kubernetes.io/version: 2021.5.1
template: template:
metadata: metadata:
labels: labels:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.5.1-rc8 app.kubernetes.io/version: 2021.5.1
spec: spec:
containers: containers:
- env: - env:
@ -88,7 +88,7 @@ spec:
secretKeyRef: secretKeyRef:
key: authentik_host_insecure key: authentik_host_insecure
name: authentik-outpost-api name: authentik-outpost-api
image: beryju/authentik-proxy:2021.5.1-rc8 image: beryju/authentik-proxy:2021.5.1
name: proxy name: proxy
ports: ports:
- containerPort: 4180 - containerPort: 4180
@ -110,7 +110,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.5.1-rc8 app.kubernetes.io/version: 2021.5.1
name: authentik-outpost name: authentik-outpost
spec: spec:
rules: rules:

View File

@ -34,7 +34,7 @@ module.exports = {
position: "left", position: "left",
}, },
{ {
href: "https://github.com/beryju/authentik", href: "https://github.com/goauthentik/authentik",
label: "GitHub", label: "GitHub",
position: "right", position: "right",
}, },
@ -69,7 +69,7 @@ module.exports = {
items: [ items: [
{ {
label: "GitHub", label: "GitHub",
href: "https://github.com/beryju/authentik", href: "https://github.com/goauthentik/authentik",
}, },
{ {
label: "Discord", label: "Discord",
@ -95,7 +95,7 @@ module.exports = {
docs: { docs: {
id: "docs", id: "docs",
sidebarPath: require.resolve("./sidebars.js"), sidebarPath: require.resolve("./sidebars.js"),
editUrl: "https://github.com/beryju/authentik/edit/master/website/", editUrl: "https://github.com/goauthentik/authentik/edit/master/website/",
}, },
theme: { theme: {
customCss: require.resolve("./src/css/custom.css"), customCss: require.resolve("./src/css/custom.css"),
@ -111,7 +111,7 @@ module.exports = {
path: 'developer-docs', path: 'developer-docs',
routeBasePath: 'developer-docs', routeBasePath: 'developer-docs',
sidebarPath: require.resolve('./sidebarsDev.js'), sidebarPath: require.resolve('./sidebarsDev.js'),
editUrl: "https://github.com/beryju/authentik/edit/master/website/", editUrl: "https://github.com/goauthentik/authentik/edit/master/website/",
}, },
], ],
], ],

8127
website/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
"serve": "docusaurus serve" "serve": "docusaurus serve"
}, },
"dependencies": { "dependencies": {
"@docusaurus/preset-classic": "2.0.0-alpha.75", "@docusaurus/preset-classic": "2.0.0-beta.0",
"@mdx-js/react": "^1.6.22", "@mdx-js/react": "^1.6.22",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"postcss": "^8.2.15", "postcss": "^8.2.15",