Compare commits
106 Commits
version/20
...
version/20
Author | SHA1 | Date | |
---|---|---|---|
276d8fe5cf | |||
92ce5f0931 | |||
7fea20375f | |||
d4d4034d2c | |||
f0db408699 | |||
5e200655d9 | |||
d5d1f2a645 | |||
cc5cc43baa | |||
e512f085db | |||
f323c01bd8 | |||
f56cacb406 | |||
eaecd31e9f | |||
36989d82e1 | |||
50777d9022 | |||
a15571bd3e | |||
26fd66d831 | |||
0be873025a | |||
28ada49910 | |||
4fc8e61f8c | |||
7d26ea1a9c | |||
3a58dc62e1 | |||
71fe7bc827 | |||
933336c38b | |||
371feb9a31 | |||
95a2fd3c9e | |||
17cb76c334 | |||
88f0dfc8cc | |||
f82aada23b | |||
ecaee92634 | |||
89252ec47b | |||
f0f25ab291 | |||
e4d0fec15a | |||
6b10baf086 | |||
f148b5d341 | |||
1471ff8940 | |||
d9a6ec2ac0 | |||
5745ffa0a8 | |||
b26202db35 | |||
6318577a51 | |||
6a2cd45847 | |||
ef5cea2c01 | |||
69f4d54bae | |||
b1eec5a7d2 | |||
1b8271d767 | |||
3e9f5ec5ef | |||
63f57b6a77 | |||
a016f99450 | |||
adc18b2991 | |||
e37a326b95 | |||
048467e97d | |||
cc2cd6919f | |||
0c6e781e5b | |||
7294d8fca5 | |||
16ec5680b4 | |||
87920fb1d7 | |||
523b96a6d2 | |||
45731d8069 | |||
e872371970 | |||
08e8cf850a | |||
b1ed2154ac | |||
7ef2aa3eb9 | |||
160139813d | |||
582ad92c76 | |||
f61736e3d1 | |||
eb02c96281 | |||
8619552920 | |||
6237352e25 | |||
2d8b4f543b | |||
8542dc10ab | |||
c55b63337c | |||
12ddee3bb6 | |||
dc41d0af27 | |||
3323b50036 | |||
8acb15a7fd | |||
f601e04b38 | |||
f50529cb5b | |||
3f1b6f9ed4 | |||
f1ab0f4314 | |||
4d1129f385 | |||
03ac9c6e16 | |||
c0839924f1 | |||
91e3aa760a | |||
5c0681d57b | |||
c4f72c2bc1 | |||
e92f9836e3 | |||
3818dc834b | |||
cda011a049 | |||
897f6f3473 | |||
b70b44490b | |||
77a5a58cb9 | |||
f3b227434e | |||
2ae164df78 | |||
9b09793230 | |||
f8a401aeca | |||
ffbab2cd68 | |||
734e5fcab4 | |||
78578c6c9d | |||
0ccec96490 | |||
8022d0801d | |||
d79975c409 | |||
20d65035d5 | |||
8d6227377f | |||
4bc50e7f57 | |||
945e42c940 | |||
052bb28086 | |||
4a84b7e2d5 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2021.8.1-rc2
|
||||
current_version = 2021.8.4
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)
|
||||
@ -23,7 +23,7 @@ values =
|
||||
|
||||
[bumpversion:file:schema.yml]
|
||||
|
||||
[bumpversion:file:.github/workflows/release.yml]
|
||||
[bumpversion:file:.github/workflows/release-publish.yml]
|
||||
|
||||
[bumpversion:file:authentik/__init__.py]
|
||||
|
||||
|
240
.github/workflows/ci-main.yml
vendored
Normal file
240
.github/workflows/ci-main.yml
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
name: authentik-ci-main
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- website
|
||||
|
||||
env:
|
||||
POSTGRES_DB: authentik
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
|
||||
|
||||
jobs:
|
||||
lint-pylint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- name: run pylint
|
||||
run: pipenv run pylint authentik tests lifecycle
|
||||
lint-black:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- name: run black
|
||||
run: pipenv run black --check authentik tests lifecycle
|
||||
lint-isort:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- name: run isort
|
||||
run: pipenv run isort --check authentik tests lifecycle
|
||||
lint-bandit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- name: run bandit
|
||||
run: pipenv run bandit -r authentik tests lifecycle
|
||||
lint-pyright:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
- name: prepare
|
||||
run: |
|
||||
scripts/ci_prepare.sh
|
||||
npm install -g pyright@1.1.136
|
||||
- name: run bandit
|
||||
run: pipenv run pyright e2e lifecycle
|
||||
test-migrations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- name: run migrations
|
||||
run: pipenv run python -m lifecycle.migrate
|
||||
test-migrations-from-stable:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: checkout stable
|
||||
run: |
|
||||
# Copy current, latest config to local
|
||||
cp authentik/lib/default.yml local.env.yml
|
||||
git checkout $(git describe --abbrev=0 --match 'version/*')
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- name: run migrations to stable
|
||||
run: pipenv run python -m lifecycle.migrate
|
||||
- name: checkout current code
|
||||
run: |
|
||||
set -x
|
||||
git checkout $GITHUB_REF
|
||||
pipenv sync --dev
|
||||
- name: migrate to latest
|
||||
run: pipenv run python -m lifecycle.migrate
|
||||
test-unittest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- uses: testspace-com/setup-testspace@v1
|
||||
with:
|
||||
domain: ${{github.repository_owner}}
|
||||
- name: run unittest
|
||||
run: |
|
||||
pipenv run make test
|
||||
pipenv run coverage xml
|
||||
- name: run testspace
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
testspace unittest.xml ?add
|
||||
- if: ${{ always() }}
|
||||
uses: codecov/codecov-action@v2
|
||||
test-integration:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: prepare
|
||||
run: scripts/ci_prepare.sh
|
||||
- uses: testspace-com/setup-testspace@v1
|
||||
with:
|
||||
domain: ${{github.repository_owner}}
|
||||
- name: prepare k3d
|
||||
run: |
|
||||
wget -q -O - https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash
|
||||
- name: run integration
|
||||
run: |
|
||||
pipenv run make test-integration
|
||||
pipenv run coverage xml
|
||||
- name: run testspace
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
testspace unittest.xml ?add
|
||||
- if: ${{ always() }}
|
||||
uses: codecov/codecov-action@v2
|
||||
test-e2e:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- uses: testspace-com/setup-testspace@v1
|
||||
with:
|
||||
domain: ${{github.repository_owner}}
|
||||
- name: prepare
|
||||
run: |
|
||||
scripts/ci_prepare.sh
|
||||
docker-compose -f tests/e2e/ci.docker-compose.yml up -d
|
||||
- name: prepare web ui
|
||||
run: |
|
||||
cd web
|
||||
npm i
|
||||
npm run build
|
||||
- name: run e2e
|
||||
run: |
|
||||
pipenv run make test-e2e
|
||||
pipenv run coverage xml
|
||||
- name: run testspace
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
testspace unittest.xml ?add
|
||||
- if: ${{ always() }}
|
||||
uses: codecov/codecov-action@v2
|
||||
report:
|
||||
if: ${{ always() }}
|
||||
needs:
|
||||
- test-unittest
|
||||
- test-integration
|
||||
- test-e2e
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: testspace-com/setup-testspace@v1
|
||||
with:
|
||||
domain: ${{github.repository_owner}}
|
||||
- name: finish testspace
|
||||
run: |
|
||||
testspace ?finish
|
||||
build:
|
||||
needs:
|
||||
- lint-pylint
|
||||
- lint-black
|
||||
- lint-isort
|
||||
- lint-bandit
|
||||
- lint-pyright
|
||||
- test-migrations
|
||||
- test-migrations-from-stable
|
||||
- test-unittest
|
||||
- test-integration
|
||||
- test-e2e
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: prepare variables
|
||||
id: ev
|
||||
run: |
|
||||
python ./scripts/gh_do_set_branch.py
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@v1
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
with:
|
||||
registry: beryju.org
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||||
- name: Building Docker Image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
tags: |
|
||||
beryju.org/authentik/server:gh-${{ steps.ev.outputs.branchName }}
|
||||
beryju.org/authentik/server:gh-${{ steps.ev.outputs.branchName }}-${{ steps.ev.outputs.timestamp }}
|
||||
build-args: |
|
||||
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}
|
66
.github/workflows/ci-outpost.yml
vendored
Normal file
66
.github/workflows/ci-outpost.yml
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
name: authentik-ci-outpost
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
lint-golint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16.3'
|
||||
- name: Generate API
|
||||
run: |
|
||||
make gen-outpost
|
||||
- name: Run linter
|
||||
run: |
|
||||
# Create folder structure for go embeds
|
||||
mkdir -p web/dist
|
||||
mkdir -p website/help
|
||||
touch web/dist/test website/help/test
|
||||
docker run \
|
||||
--rm \
|
||||
-v $(pwd):/app \
|
||||
-w /app \
|
||||
golangci/golangci-lint:v1.39.0 \
|
||||
golangci-lint run -v --timeout 200s
|
||||
build:
|
||||
needs:
|
||||
- lint-golint
|
||||
strategy:
|
||||
matrix:
|
||||
type:
|
||||
- proxy
|
||||
- ldap
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: prepare variables
|
||||
id: ev
|
||||
run: |
|
||||
python ./scripts/gh_do_set_branch.py
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@v1
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
with:
|
||||
registry: beryju.org
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||||
- name: Building Docker Image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
tags: |
|
||||
beryju.org/authentik/outpost-${{ matrix.type }}:gh-${{ steps.ev.outputs.branchName }}
|
||||
beryju.org/authentik/outpost-${{ matrix.type }}:gh-${{ steps.ev.outputs.branchName }}-${{ steps.ev.outputs.timestamp }}
|
||||
beryju.org/authentik/outpost-${{ matrix.type }}:gh-${{ steps.ev.outputs.sha }}
|
||||
file: ${{ matrix.type }}.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}
|
82
.github/workflows/ci-web.yml
vendored
Normal file
82
.github/workflows/ci-web.yml
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
name: authentik-ci-web
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
lint-eslint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- run: |
|
||||
cd web
|
||||
npm install
|
||||
- name: Generate API
|
||||
run: make gen-web
|
||||
- name: Eslint
|
||||
run: |
|
||||
cd web
|
||||
npm run lint
|
||||
lint-prettier:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- run: |
|
||||
cd web
|
||||
npm install
|
||||
- name: Generate API
|
||||
run: make gen-web
|
||||
- name: prettier
|
||||
run: |
|
||||
cd web
|
||||
npm run prettier-check
|
||||
lint-lit-analyse:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- run: |
|
||||
cd web
|
||||
npm install
|
||||
- name: Generate API
|
||||
run: make gen-web
|
||||
- name: prettier
|
||||
run: |
|
||||
cd web
|
||||
npm run lit-analyse
|
||||
build:
|
||||
needs:
|
||||
- lint-eslint
|
||||
- lint-prettier
|
||||
- lint-lit-analyse
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- run: |
|
||||
cd web
|
||||
npm install
|
||||
- name: Generate API
|
||||
run: make gen-web
|
||||
- name: build
|
||||
run: |
|
||||
cd web
|
||||
npm run build
|
@ -33,14 +33,14 @@ jobs:
|
||||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik:2021.8.1-rc2,
|
||||
beryju/authentik:2021.8.4,
|
||||
beryju/authentik:latest,
|
||||
ghcr.io/goauthentik/server:2021.8.1-rc2,
|
||||
ghcr.io/goauthentik/server:2021.8.4,
|
||||
ghcr.io/goauthentik/server:latest
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
- name: Building Docker Image (stable)
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.8.1-rc2', 'rc') }}
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.8.4', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik:latest
|
||||
docker tag beryju/authentik:latest beryju/authentik:stable
|
||||
@ -75,14 +75,14 @@ jobs:
|
||||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-proxy:2021.8.1-rc2,
|
||||
beryju/authentik-proxy:2021.8.4,
|
||||
beryju/authentik-proxy:latest,
|
||||
ghcr.io/goauthentik/proxy:2021.8.1-rc2,
|
||||
ghcr.io/goauthentik/proxy:2021.8.4,
|
||||
ghcr.io/goauthentik/proxy:latest
|
||||
file: proxy.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Building Docker Image (stable)
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.8.1-rc2', 'rc') }}
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.8.4', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik-proxy:latest
|
||||
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
|
||||
@ -117,14 +117,14 @@ jobs:
|
||||
with:
|
||||
push: ${{ github.event_name == 'release' }}
|
||||
tags: |
|
||||
beryju/authentik-ldap:2021.8.1-rc2,
|
||||
beryju/authentik-ldap:2021.8.4,
|
||||
beryju/authentik-ldap:latest,
|
||||
ghcr.io/goauthentik/ldap:2021.8.1-rc2,
|
||||
ghcr.io/goauthentik/ldap:2021.8.4,
|
||||
ghcr.io/goauthentik/ldap:latest
|
||||
file: ldap.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Building Docker Image (stable)
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.8.1-rc2', 'rc') }}
|
||||
if: ${{ github.event_name == 'release' && !contains('2021.8.4', 'rc') }}
|
||||
run: |
|
||||
docker pull beryju/authentik-ldap:latest
|
||||
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
|
||||
@ -175,7 +175,7 @@ jobs:
|
||||
SENTRY_PROJECT: authentik
|
||||
SENTRY_URL: https://sentry.beryju.org
|
||||
with:
|
||||
version: authentik@2021.8.1-rc2
|
||||
version: authentik@2021.8.4
|
||||
environment: beryjuorg-prod
|
||||
sourcemaps: './web/dist'
|
||||
url_prefix: '~/static/dist'
|
2
.github/workflows/web-api-publish.yml
vendored
2
.github/workflows/web-api-publish.yml
vendored
@ -1,7 +1,7 @@
|
||||
name: authentik-web-api-publish
|
||||
on:
|
||||
push:
|
||||
branches: [ master, version* ]
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'schema.yml'
|
||||
jobs:
|
||||
|
@ -11,8 +11,8 @@ The following is a set of guidelines for contributing to authentik and its compo
|
||||
[I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
|
||||
|
||||
[What should I know before I get started?](#what-should-i-know-before-i-get-started)
|
||||
* [Atom and Packages](#atom-and-packages)
|
||||
* [Atom Design Decisions](#design-decisions)
|
||||
* [The components](#the-components)
|
||||
* [authentik's structure](#authentiks-structure)
|
||||
|
||||
[How Can I Contribute?](#how-can-i-contribute)
|
||||
* [Reporting Bugs](#reporting-bugs)
|
||||
@ -22,14 +22,9 @@ The following is a set of guidelines for contributing to authentik and its compo
|
||||
|
||||
[Styleguides](#styleguides)
|
||||
* [Git Commit Messages](#git-commit-messages)
|
||||
* [JavaScript Styleguide](#javascript-styleguide)
|
||||
* [CoffeeScript Styleguide](#coffeescript-styleguide)
|
||||
* [Specs Styleguide](#specs-styleguide)
|
||||
* [Python Styleguide](#python-styleguide)
|
||||
* [Documentation Styleguide](#documentation-styleguide)
|
||||
|
||||
[Additional Notes](#additional-notes)
|
||||
* [Issue and Pull Request Labels](#issue-and-pull-request-labels)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Basically, don't be a dickhead. This is an open-source non-profit project, that is made in the free time of Volunteers. If there's something you dislike or think can be done better, tell us! We'd love to hear any suggestions for improvement.
|
||||
|
189
Pipfile.lock
generated
189
Pipfile.lock
generated
@ -122,19 +122,19 @@
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:7209b79833bdf13753aa24f76bf533890ffed2cc4fe1fe08619d223c209bbd11",
|
||||
"sha256:f46c93d09acd4d4bfc6b9522ed852fecbdc508e0365f29ddfb3c146aae784b4e"
|
||||
"sha256:5116e9bdec19adcc5531a9b7b535be77d5314eef092aaf7033ace48a9be65036",
|
||||
"sha256:658ddf4ba552f654fd4d48335fa95ff4e3e1a4e82f90021a1a1d3de4a5428ba4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.18.27"
|
||||
"version": "==1.18.34"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:8c99abd7093ab11ce8d09c68732aeeb6065a53d2fe371568452e99291817fff5",
|
||||
"sha256:b9e2c90bad164d111c229102f58f995c28576e719dd116b446965e1b786f8fa5"
|
||||
"sha256:1b4999fb0e1a4c050c4d9118ebdaac8d83761ef32c3c0f13a25f9204045998fe",
|
||||
"sha256:ec2cdf1c8ed64a7f392f352125d248c76103fa9d137b275b7c76836776cedf56"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.21.27"
|
||||
"version": "==1.21.34"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
@ -305,22 +305,25 @@
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
|
||||
"sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959",
|
||||
"sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6",
|
||||
"sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873",
|
||||
"sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2",
|
||||
"sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713",
|
||||
"sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1",
|
||||
"sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177",
|
||||
"sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250",
|
||||
"sha256:b01fd6f2737816cb1e08ed4807ae194404790eac7ad030b34f2ce72b332f5586",
|
||||
"sha256:bf40af59ca2465b24e54f671b2de2c59257ddc4f7e5706dbd6930e26823668d3",
|
||||
"sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca",
|
||||
"sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d",
|
||||
"sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"
|
||||
"sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e",
|
||||
"sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b",
|
||||
"sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7",
|
||||
"sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085",
|
||||
"sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc",
|
||||
"sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a",
|
||||
"sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498",
|
||||
"sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9",
|
||||
"sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c",
|
||||
"sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7",
|
||||
"sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb",
|
||||
"sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14",
|
||||
"sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af",
|
||||
"sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e",
|
||||
"sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5",
|
||||
"sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06",
|
||||
"sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"
|
||||
],
|
||||
"version": "==3.4.7"
|
||||
"version": "==3.4.8"
|
||||
},
|
||||
"dacite": {
|
||||
"hashes": [
|
||||
@ -356,11 +359,11 @@
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:7f92413529aa0e291f3be78ab19be31aefb1e1c9a52cd59e130f505f27a51f13",
|
||||
"sha256:f27f8544c9d4c383bbe007c57e3235918e258364577373d4920e9162837be022"
|
||||
"sha256:95b318319d6997bac3595517101ad9cc83fe5672ac498ba48d1a410f47afecd2",
|
||||
"sha256:e93c93565005b37ddebf2396b4dc4b6913c1838baa82efdfb79acedd5816c240"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.6"
|
||||
"version": "==3.2.7"
|
||||
},
|
||||
"django-dbbackup": {
|
||||
"git": "https://github.com/django-dbbackup/django-dbbackup.git",
|
||||
@ -440,19 +443,19 @@
|
||||
},
|
||||
"docker": {
|
||||
"hashes": [
|
||||
"sha256:3e8bc47534e0ca9331d72c32f2881bb13b93ded0bcdeab3c833fb7cf61c0a9a5",
|
||||
"sha256:fc961d622160e8021c10d1bcabc388c57d55fb1f917175afbe24af442e6879bd"
|
||||
"sha256:5aafaec0d2a1de0e32010b43b5eac9f6f851c9db99a46ad32b8e44eeeb55616d",
|
||||
"sha256:b88eef725b33c0ed59c67506631bbb09b480b7ca5a739bbbb948b446443fe914"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.0.0"
|
||||
"version": "==5.0.1"
|
||||
},
|
||||
"drf-spectacular": {
|
||||
"hashes": [
|
||||
"sha256:f080128c42183fcaed6b9e8e5afcd2e5cd68426b1f80bfc85938f25e62db7fe5",
|
||||
"sha256:fb19aa69fcfcd37b0c9dfb9989c0671e1bb47af332ca2171378c7f840263788c"
|
||||
"sha256:98681add6671db9e6dba5f0d3dcf8aab5950cbb978497390507356e593bf082f",
|
||||
"sha256:a430bab0f4ecfc90786b7b63bbee3f9a56094201fbed9bdfbf952e99e6469104"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.17.3"
|
||||
"version": "==0.18.1"
|
||||
},
|
||||
"duo-client": {
|
||||
"hashes": [
|
||||
@ -487,11 +490,11 @@
|
||||
},
|
||||
"google-auth": {
|
||||
"hashes": [
|
||||
"sha256:c012c8be7c442c8309ca8fa0876fef33f5fd977c467be1e1c1c2f721e8ebd73c",
|
||||
"sha256:ea1af050b3e06eb73e4470f704d23007307bc0e87c13e015f6b90460f1407bd3"
|
||||
"sha256:104475dc4d57bbae49017aea16fffbb763204fa2d6a70f1f3cc79962c1a383a4",
|
||||
"sha256:cde472372e030e1e0bc64dac00fb53e6c095d7ab641f4281e2c995e85e205d8b"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
@ -1148,11 +1151,11 @@
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
|
||||
"sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
|
||||
"sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
|
||||
"sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
|
||||
"sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
|
||||
"sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
|
||||
],
|
||||
"version": "==3.10.0.0"
|
||||
"version": "==3.10.0.2"
|
||||
},
|
||||
"ua-parser": {
|
||||
"hashes": [
|
||||
@ -1417,11 +1420,11 @@
|
||||
},
|
||||
"astroid": {
|
||||
"hashes": [
|
||||
"sha256:b6c2d75cd7c2982d09e7d41d70213e863b3ba34d3bd4014e08f167cee966e99e",
|
||||
"sha256:ecc50f9b3803ebf8ea19aa2c6df5622d8a5c31456a53c741d3be044d96ff0948"
|
||||
"sha256:3b680ce0419b8a771aba6190139a3998d14b413852506d99aff8dc2bf65ee67c",
|
||||
"sha256:dc1e8b28427d6bbef6b8842b18765ab58f558c42bb80540bd7648c98412af25e"
|
||||
],
|
||||
"markers": "python_version ~= '3.6'",
|
||||
"version": "==2.7.2"
|
||||
"version": "==2.7.3"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
@ -1579,7 +1582,7 @@
|
||||
"sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899",
|
||||
"sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"
|
||||
],
|
||||
"markers": "python_version < '4.0' and python_full_version >= '3.6.1'",
|
||||
"markers": "python_version < '4' and python_full_version >= '3.6.1'",
|
||||
"version": "==5.9.3"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
@ -1649,19 +1652,19 @@
|
||||
},
|
||||
"platformdirs": {
|
||||
"hashes": [
|
||||
"sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c",
|
||||
"sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"
|
||||
"sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f",
|
||||
"sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.2.0"
|
||||
"version": "==2.3.0"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
|
||||
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.13.1"
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
@ -1704,11 +1707,11 @@
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b",
|
||||
"sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"
|
||||
"sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89",
|
||||
"sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.2.4"
|
||||
"version": "==6.2.5"
|
||||
},
|
||||
"pytest-django": {
|
||||
"hashes": [
|
||||
@ -1755,49 +1758,49 @@
|
||||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:03840a07a402576b8e3a6261f17eb88abd653ad4e18ec46ef10c9a63f8c99ebd",
|
||||
"sha256:06ba444bbf7ede3890a912bd4904bb65bf0da8f0d8808b90545481362c978642",
|
||||
"sha256:1f9974826aeeda32a76648fc677e3125ade379869a84aa964b683984a2dea9f1",
|
||||
"sha256:330836ad89ff0be756b58758878409f591d4737b6a8cef26a162e2a4961c3321",
|
||||
"sha256:38600fd58c2996829480de7d034fb2d3a0307110e44dae80b6b4f9b3d2eea529",
|
||||
"sha256:3a195e26df1fbb40ebee75865f9b64ba692a5824ecb91c078cc665b01f7a9a36",
|
||||
"sha256:41acdd6d64cd56f857e271009966c2ffcbd07ec9149ca91f71088574eaa4278a",
|
||||
"sha256:45f97ade892ace20252e5ccecdd7515c7df5feeb42c3d2a8b8c55920c3551c30",
|
||||
"sha256:4b0c211c55d4aac4309c3209833c803fada3fc21cdf7b74abedda42a0c9dc3ce",
|
||||
"sha256:5d5209c3ba25864b1a57461526ebde31483db295fc6195fdfc4f8355e10f7376",
|
||||
"sha256:615fb5a524cffc91ab4490b69e10ae76c1ccbfa3383ea2fad72e54a85c7d47dd",
|
||||
"sha256:61e734c2bcb3742c3f454dfa930ea60ea08f56fd1a0eb52d8cb189a2f6be9586",
|
||||
"sha256:640ccca4d0a6fcc6590f005ecd7b16c3d8f5d52174e4854f96b16f34c39d6cb7",
|
||||
"sha256:6dbd51c3db300ce9d3171f4106da18fe49e7045232630fe3d4c6e37cb2b39ab9",
|
||||
"sha256:71a904da8c9c02aee581f4452a5a988c3003207cb8033db426f29e5b2c0b7aea",
|
||||
"sha256:8021dee64899f993f4b5cca323aae65aabc01a546ed44356a0965e29d7893c94",
|
||||
"sha256:8b8d551f1bd60b3e1c59ff55b9e8d74607a5308f66e2916948cafd13480b44a3",
|
||||
"sha256:93f9f720081d97acee38a411e861d4ce84cbc8ea5319bc1f8e38c972c47af49f",
|
||||
"sha256:96f0c79a70642dfdf7e6a018ebcbea7ea5205e27d8e019cad442d2acfc9af267",
|
||||
"sha256:9966337353e436e6ba652814b0a957a517feb492a98b8f9d3b6ba76d22301dcc",
|
||||
"sha256:a34ba9e39f8269fd66ab4f7a802794ffea6d6ac500568ec05b327a862c21ce23",
|
||||
"sha256:a49f85f0a099a5755d0a2cc6fc337e3cb945ad6390ec892332c691ab0a045882",
|
||||
"sha256:a795829dc522227265d72b25d6ee6f6d41eb2105c15912c230097c8f5bfdbcdc",
|
||||
"sha256:a89ca4105f8099de349d139d1090bad387fe2b208b717b288699ca26f179acbe",
|
||||
"sha256:ac95101736239260189f426b1e361dc1b704513963357dc474beb0f39f5b7759",
|
||||
"sha256:ae87ab669431f611c56e581679db33b9a467f87d7bf197ac384e71e4956b4456",
|
||||
"sha256:b091dcfee169ad8de21b61eb2c3a75f9f0f859f851f64fdaf9320759a3244239",
|
||||
"sha256:b511c6009d50d5c0dd0bab85ed25bc8ad6b6f5611de3a63a59786207e82824bb",
|
||||
"sha256:b79dc2b2e313565416c1e62807c7c25c67a6ff0a0f8d83a318df464555b65948",
|
||||
"sha256:bca14dfcfd9aae06d7d8d7e105539bd77d39d06caaae57a1ce945670bae744e0",
|
||||
"sha256:c835c30f3af5c63a80917b72115e1defb83de99c73bc727bddd979a3b449e183",
|
||||
"sha256:ccd721f1d4fc42b541b633d6e339018a08dd0290dc67269df79552843a06ca92",
|
||||
"sha256:d6c2b1d78ceceb6741d703508cd0e9197b34f6bf6864dab30f940f8886e04ade",
|
||||
"sha256:d6ec4ae13760ceda023b2e5ef1f9bc0b21e4b0830458db143794a117fdbdc044",
|
||||
"sha256:d8b623fc429a38a881ab2d9a56ef30e8ea20c72a891c193f5ebbddc016e083ee",
|
||||
"sha256:ea9753d64cba6f226947c318a923dadaf1e21cd8db02f71652405263daa1f033",
|
||||
"sha256:ebbceefbffae118ab954d3cd6bf718f5790db66152f95202ebc231d58ad4e2c2",
|
||||
"sha256:ecb6e7c45f9cd199c10ec35262b53b2247fb9a408803ed00ee5bb2b54aa626f5",
|
||||
"sha256:ef9326c64349e2d718373415814e754183057ebc092261387a2c2f732d9172b2",
|
||||
"sha256:f93a9d8804f4cec9da6c26c8cfae2c777028b4fdd9f49de0302e26e00bb86504",
|
||||
"sha256:faf08b0341828f6a29b8f7dd94d5cf8cc7c39bfc3e67b78514c54b494b66915a"
|
||||
"sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468",
|
||||
"sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354",
|
||||
"sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308",
|
||||
"sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d",
|
||||
"sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc",
|
||||
"sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8",
|
||||
"sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797",
|
||||
"sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2",
|
||||
"sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13",
|
||||
"sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d",
|
||||
"sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a",
|
||||
"sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0",
|
||||
"sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73",
|
||||
"sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1",
|
||||
"sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed",
|
||||
"sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a",
|
||||
"sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b",
|
||||
"sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f",
|
||||
"sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256",
|
||||
"sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb",
|
||||
"sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2",
|
||||
"sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983",
|
||||
"sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb",
|
||||
"sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645",
|
||||
"sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8",
|
||||
"sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a",
|
||||
"sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906",
|
||||
"sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f",
|
||||
"sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c",
|
||||
"sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892",
|
||||
"sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0",
|
||||
"sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e",
|
||||
"sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e",
|
||||
"sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed",
|
||||
"sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c",
|
||||
"sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374",
|
||||
"sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd",
|
||||
"sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791",
|
||||
"sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a",
|
||||
"sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1",
|
||||
"sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"
|
||||
],
|
||||
"version": "==2021.8.21"
|
||||
"version": "==2021.8.28"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
|
@ -5,13 +5,14 @@
|
||||
---
|
||||
|
||||
[](https://discord.gg/jg33eMhnj6)
|
||||
[](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=6)
|
||||
[](https://dev.azure.com/beryjuorg/authentik/_build?definitionId=6)
|
||||

|
||||

|
||||

|
||||
[](https://codecov.io/gh/goauthentik/authentik)
|
||||

|
||||

|
||||

|
||||
[Transifex](https://www.transifex.com/beryjuorg/authentik/)
|
||||
[](https://www.transifex.com/beryjuorg/authentik/)
|
||||
|
||||
## What is authentik?
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
"""authentik"""
|
||||
__version__ = "2021.8.1-rc2"
|
||||
__version__ = "2021.8.4"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
@ -1,8 +1,10 @@
|
||||
"""authentik api urls"""
|
||||
from django.urls import include, path
|
||||
|
||||
from authentik.api.v2.urls import urlpatterns as v2_urls
|
||||
from authentik.api.v3.urls import urlpatterns as v3_urls
|
||||
|
||||
urlpatterns = [
|
||||
path("v2beta/", include(v2_urls)),
|
||||
# Remove in 2022.1
|
||||
path("v2beta/", include(v3_urls)),
|
||||
path("v3/", include(v3_urls)),
|
||||
]
|
||||
|
@ -4,16 +4,44 @@ from json import loads
|
||||
from django.conf import settings
|
||||
from django.http.request import HttpRequest
|
||||
from django.http.response import HttpResponse
|
||||
from django.views.generic.base import View
|
||||
from requests import post
|
||||
from requests.exceptions import RequestException
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.parsers import BaseParser
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.throttling import AnonRateThrottle
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from authentik.lib.config import CONFIG
|
||||
|
||||
|
||||
class SentryTunnelView(View):
|
||||
class PlainTextParser(BaseParser):
|
||||
"""Plain text parser."""
|
||||
|
||||
media_type = "text/plain"
|
||||
|
||||
def parse(self, stream, media_type=None, parser_context=None) -> str:
|
||||
"""Simply return a string representing the body of the request."""
|
||||
return stream.read()
|
||||
|
||||
|
||||
class CsrfExemptSessionAuthentication(SessionAuthentication):
|
||||
"""CSRF-exempt Session authentication"""
|
||||
|
||||
def enforce_csrf(self, request: Request):
|
||||
return # To not perform the csrf check previously happening
|
||||
|
||||
|
||||
class SentryTunnelView(APIView):
|
||||
"""Sentry tunnel, to prevent ad blockers from blocking sentry"""
|
||||
|
||||
serializer_class = None
|
||||
parser_classes = [PlainTextParser]
|
||||
throttle_classes = [AnonRateThrottle]
|
||||
permission_classes = [AllowAny]
|
||||
authentication_classes = [CsrfExemptSessionAuthentication]
|
||||
|
||||
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
"""Sentry tunnel, to prevent ad blockers from blocking sentry"""
|
||||
# Only allow usage of this endpoint when error reporting is enabled
|
@ -1,4 +1,4 @@
|
||||
"""api v2 urls"""
|
||||
"""api v3 urls"""
|
||||
from django.urls import path
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from drf_spectacular.views import SpectacularAPIView
|
||||
@ -10,8 +10,8 @@ from authentik.admin.api.system import SystemView
|
||||
from authentik.admin.api.tasks import TaskViewSet
|
||||
from authentik.admin.api.version import VersionView
|
||||
from authentik.admin.api.workers import WorkerView
|
||||
from authentik.api.v2.config import ConfigView
|
||||
from authentik.api.v2.sentry import SentryTunnelView
|
||||
from authentik.api.v3.config import ConfigView
|
||||
from authentik.api.v3.sentry import SentryTunnelView
|
||||
from authentik.api.views import APIBrowserView
|
||||
from authentik.core.api.applications import ApplicationViewSet
|
||||
from authentik.core.api.authenticated_sessions import AuthenticatedSessionViewSet
|
@ -4,14 +4,9 @@ from django.db.models import QuerySet
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import (
|
||||
OpenApiParameter,
|
||||
OpenApiResponse,
|
||||
extend_schema,
|
||||
inline_serializer,
|
||||
)
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, FileField, ReadOnlyField
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
@ -24,6 +19,7 @@ from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h
|
||||
from authentik.api.decorators import permission_required
|
||||
from authentik.core.api.providers import ProviderSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import FilePathSerializer, FileUploadSerializer
|
||||
from authentik.core.models import Application, User
|
||||
from authentik.events.models import EventAction
|
||||
from authentik.policies.api.exec import PolicyTestResultSerializer
|
||||
@ -180,13 +176,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
|
||||
@permission_required("authentik_core.change_application")
|
||||
@extend_schema(
|
||||
request={
|
||||
"multipart/form-data": inline_serializer(
|
||||
"SetIcon",
|
||||
fields={
|
||||
"file": FileField(required=False),
|
||||
"clear": BooleanField(default=False),
|
||||
},
|
||||
)
|
||||
"multipart/form-data": FileUploadSerializer,
|
||||
},
|
||||
responses={
|
||||
200: OpenApiResponse(description="Success"),
|
||||
@ -218,7 +208,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
|
||||
|
||||
@permission_required("authentik_core.change_application")
|
||||
@extend_schema(
|
||||
request=inline_serializer("SetIconURL", fields={"url": CharField()}),
|
||||
request=FilePathSerializer,
|
||||
responses={
|
||||
200: OpenApiResponse(description="Success"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
|
@ -23,10 +23,12 @@ from authentik.managed.api import ManagedSerializer
|
||||
class TokenSerializer(ManagedSerializer, ModelSerializer):
|
||||
"""Token Serializer"""
|
||||
|
||||
user = UserSerializer(required=False)
|
||||
user_obj = UserSerializer(required=False, source="user")
|
||||
|
||||
def validate(self, attrs: dict[Any, str]) -> dict[Any, str]:
|
||||
"""Ensure only API or App password tokens are created."""
|
||||
request: Request = self.context["request"]
|
||||
attrs.setdefault("user", request.user)
|
||||
attrs.setdefault("intent", TokenIntents.INTENT_API)
|
||||
if attrs.get("intent") not in [TokenIntents.INTENT_API, TokenIntents.INTENT_APP_PASSWORD]:
|
||||
raise ValidationError(f"Invalid intent {attrs.get('intent')}")
|
||||
@ -41,11 +43,14 @@ class TokenSerializer(ManagedSerializer, ModelSerializer):
|
||||
"identifier",
|
||||
"intent",
|
||||
"user",
|
||||
"user_obj",
|
||||
"description",
|
||||
"expires",
|
||||
"expiring",
|
||||
]
|
||||
depth = 2
|
||||
extra_kwargs = {
|
||||
"user": {"required": False},
|
||||
}
|
||||
|
||||
|
||||
class TokenViewSerializer(PassiveSerializer):
|
||||
|
@ -310,7 +310,9 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
||||
# since it caches the full object
|
||||
if SESSION_IMPERSONATE_USER in request.session:
|
||||
request.session[SESSION_IMPERSONATE_USER] = new_user
|
||||
return self.me(request)
|
||||
serializer = SessionUserSerializer(data={"user": UserSelfSerializer(request.user).data})
|
||||
serializer.is_valid()
|
||||
return Response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
|
||||
@extend_schema(responses={200: UserMetricsSerializer(many=False)})
|
||||
|
@ -2,7 +2,7 @@
|
||||
from typing import Any
|
||||
|
||||
from django.db.models import Model
|
||||
from rest_framework.fields import CharField, IntegerField
|
||||
from rest_framework.fields import BooleanField, CharField, FileField, IntegerField
|
||||
from rest_framework.serializers import Serializer, SerializerMethodField, ValidationError
|
||||
|
||||
|
||||
@ -22,8 +22,18 @@ class PassiveSerializer(Serializer):
|
||||
def update(self, instance: Model, validated_data: dict) -> Model: # pragma: no cover
|
||||
return Model()
|
||||
|
||||
class Meta:
|
||||
model = Model
|
||||
|
||||
class FileUploadSerializer(PassiveSerializer):
|
||||
"""Serializer to upload file"""
|
||||
|
||||
file = FileField(required=False)
|
||||
clear = BooleanField(default=False)
|
||||
|
||||
|
||||
class FilePathSerializer(PassiveSerializer):
|
||||
"""Serializer to upload file"""
|
||||
|
||||
url = CharField()
|
||||
|
||||
|
||||
class MetaNameSerializer(PassiveSerializer):
|
||||
|
@ -11,6 +11,7 @@ from django.core.cache import cache
|
||||
from prometheus_client import Gauge
|
||||
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.lib.utils.errors import exception_to_string
|
||||
|
||||
GAUGE_TASKS = Gauge(
|
||||
"authentik_system_tasks",
|
||||
@ -174,9 +175,7 @@ class MonitoredTask(Task):
|
||||
).save(self.result_timeout_hours)
|
||||
Event.new(
|
||||
EventAction.SYSTEM_TASK_EXCEPTION,
|
||||
message=(
|
||||
f"Task {self.__name__} encountered an error: " "\n".join(self._result.messages)
|
||||
),
|
||||
message=(f"Task {self.__name__} encountered an error: {exception_to_string(exc)}"),
|
||||
).save()
|
||||
return super().on_failure(exc, task_id, args, kwargs, einfo=einfo)
|
||||
|
||||
|
@ -7,10 +7,10 @@ from django.http.response import HttpResponseBadRequest, JsonResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, FileField, ReadOnlyField
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
@ -20,7 +20,12 @@ from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.api.decorators import permission_required
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import CacheSerializer, LinkSerializer
|
||||
from authentik.core.api.utils import (
|
||||
CacheSerializer,
|
||||
FilePathSerializer,
|
||||
FileUploadSerializer,
|
||||
LinkSerializer,
|
||||
)
|
||||
from authentik.flows.exceptions import FlowNonApplicableException
|
||||
from authentik.flows.models import Flow
|
||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner, cache_key
|
||||
@ -147,7 +152,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
|
||||
],
|
||||
)
|
||||
@extend_schema(
|
||||
request={"multipart/form-data": inline_serializer("SetIcon", fields={"file": FileField()})},
|
||||
request={"multipart/form-data": FileUploadSerializer},
|
||||
responses={
|
||||
204: OpenApiResponse(description="Successfully imported flow"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
@ -259,13 +264,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
|
||||
@permission_required("authentik_flows.change_flow")
|
||||
@extend_schema(
|
||||
request={
|
||||
"multipart/form-data": inline_serializer(
|
||||
"SetIcon",
|
||||
fields={
|
||||
"file": FileField(required=False),
|
||||
"clear": BooleanField(default=False),
|
||||
},
|
||||
)
|
||||
"multipart/form-data": FileUploadSerializer,
|
||||
},
|
||||
responses={
|
||||
200: OpenApiResponse(description="Success"),
|
||||
@ -301,7 +300,7 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
|
||||
|
||||
@permission_required("authentik_core.change_application")
|
||||
@extend_schema(
|
||||
request=inline_serializer("SetIconURL", fields={"url": CharField()}),
|
||||
request=FilePathSerializer,
|
||||
responses={
|
||||
200: OpenApiResponse(description="Success"),
|
||||
400: OpenApiResponse(description="Bad request"),
|
||||
|
@ -31,6 +31,7 @@ class FlowPlanProcess(PROCESS_CLASS): # pragma: no cover
|
||||
self.request = RequestFactory().get("/")
|
||||
|
||||
def run(self):
|
||||
"""Execute 1000 flow plans"""
|
||||
print(f"Proc {self.index} Running")
|
||||
|
||||
def test_inner():
|
||||
|
@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.6 on 2021-08-30 14:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_flows", "0023_alter_flow_background"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="flow",
|
||||
name="compatibility_mode",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="Enable compatibility mode, increases compatibility with password managers on mobile devices.",
|
||||
),
|
||||
),
|
||||
]
|
@ -125,7 +125,7 @@ class Flow(SerializerModel, PolicyBindingModel):
|
||||
)
|
||||
|
||||
compatibility_mode = models.BooleanField(
|
||||
default=True,
|
||||
default=False,
|
||||
help_text=_(
|
||||
"Enable compatibility mode, increases compatibility with "
|
||||
"password managers on mobile devices."
|
||||
|
@ -2,10 +2,10 @@
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -37,7 +37,7 @@ def to_stage_response(request: HttpRequest, source: HttpResponse):
|
||||
TO_STAGE_RESPONSE_MOCK = MagicMock(side_effect=to_stage_response)
|
||||
|
||||
|
||||
class TestFlowExecutor(TestCase):
|
||||
class TestFlowExecutor(APITestCase):
|
||||
"""Test views logic"""
|
||||
|
||||
def setUp(self):
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""flow views tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from authentik.flows.models import Flow, FlowDesignation
|
||||
@ -10,9 +10,6 @@ from authentik.flows.views import SESSION_KEY_PLAN
|
||||
class TestHelperView(TestCase):
|
||||
"""Test helper views logic"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def test_default_view(self):
|
||||
"""Test that ToDefaultFlow returns the expected URL"""
|
||||
flow = Flow.objects.filter(
|
||||
|
@ -29,7 +29,9 @@ class DockerController(BaseController):
|
||||
raise ControllerException from exc
|
||||
|
||||
def _get_labels(self) -> dict[str, str]:
|
||||
return {}
|
||||
return {
|
||||
"io.goauthentik.outpost-uuid": self.outpost.pk.hex,
|
||||
}
|
||||
|
||||
def _get_env(self) -> dict[str, str]:
|
||||
return {
|
||||
@ -49,6 +51,17 @@ class DockerController(BaseController):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _comp_labels(self, container: Container) -> bool:
|
||||
"""Check if container's labels is equal to what we would set. Return true if container needs
|
||||
to be rebuilt."""
|
||||
should_be = self._get_labels()
|
||||
for key, expected_value in should_be.items():
|
||||
if key not in container.labels:
|
||||
return True
|
||||
if container.labels[key] != expected_value:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _comp_ports(self, container: Container) -> bool:
|
||||
"""Check that the container has the correct ports exposed. Return true if container needs
|
||||
to be rebuilt."""
|
||||
@ -92,9 +105,11 @@ class DockerController(BaseController):
|
||||
"environment": self._get_env(),
|
||||
"labels": self._get_labels(),
|
||||
"restart_policy": {"Name": "unless-stopped"},
|
||||
"network": self.outpost.config.docker_network,
|
||||
}
|
||||
if settings.TEST:
|
||||
del container_args["ports"]
|
||||
del container_args["network"]
|
||||
container_args["network_mode"] = "host"
|
||||
return (
|
||||
self.client.containers.create(**container_args),
|
||||
@ -133,6 +148,11 @@ class DockerController(BaseController):
|
||||
self.logger.info("Container has outdated config, re-creating...")
|
||||
self.down()
|
||||
return self.up(depth + 1)
|
||||
# Check that container values match our values
|
||||
if self._comp_labels(container):
|
||||
self.logger.info("Container has outdated labels, re-creating...")
|
||||
self.down()
|
||||
return self.up(depth + 1)
|
||||
if (
|
||||
container.attrs.get("HostConfig", {})
|
||||
.get("RestartPolicy", {})
|
||||
|
@ -3,10 +3,11 @@ from typing import TYPE_CHECKING, Generic, TypeVar
|
||||
|
||||
from django.utils.text import slugify
|
||||
from kubernetes.client import V1ObjectMeta
|
||||
from kubernetes.client.exceptions import ApiException, OpenApiException
|
||||
from kubernetes.client.models.v1_deployment import V1Deployment
|
||||
from kubernetes.client.models.v1_pod import V1Pod
|
||||
from kubernetes.client.rest import ApiException
|
||||
from structlog.stdlib import get_logger
|
||||
from urllib3.exceptions import HTTPError
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.lib.sentry import SentryIgnoredException
|
||||
@ -72,8 +73,9 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
try:
|
||||
try:
|
||||
current = self.retrieve()
|
||||
except ApiException as exc:
|
||||
if exc.status == 404:
|
||||
except (OpenApiException, HTTPError) as exc:
|
||||
# pylint: disable=no-member
|
||||
if isinstance(exc, ApiException) and exc.status == 404:
|
||||
self.logger.debug("Failed to get current, triggering recreate")
|
||||
raise NeedsRecreate from exc
|
||||
self.logger.debug("Other unhandled error", exc=exc)
|
||||
@ -104,8 +106,9 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
current = self.retrieve()
|
||||
self.delete(current)
|
||||
self.logger.debug("Removing")
|
||||
except ApiException as exc:
|
||||
if exc.status == 404:
|
||||
except (OpenApiException, HTTPError) as exc:
|
||||
# pylint: disable=no-member
|
||||
if isinstance(exc, ApiException) and exc.status == 404:
|
||||
self.logger.debug("Failed to get current, assuming non-existant")
|
||||
return
|
||||
self.logger.debug("Other unhandled error", exc=exc)
|
||||
|
@ -3,8 +3,9 @@ from io import StringIO
|
||||
from typing import Type
|
||||
|
||||
from kubernetes.client.api_client import ApiClient
|
||||
from kubernetes.client.exceptions import ApiException
|
||||
from kubernetes.client.exceptions import OpenApiException
|
||||
from structlog.testing import capture_logs
|
||||
from urllib3.exceptions import HTTPError
|
||||
from yaml import dump_all
|
||||
|
||||
from authentik.outposts.controllers.base import BaseController, ControllerException
|
||||
@ -12,7 +13,7 @@ from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
|
||||
from authentik.outposts.controllers.k8s.deployment import DeploymentReconciler
|
||||
from authentik.outposts.controllers.k8s.secret import SecretReconciler
|
||||
from authentik.outposts.controllers.k8s.service import ServiceReconciler
|
||||
from authentik.outposts.models import KubernetesServiceConnection, Outpost
|
||||
from authentik.outposts.models import KubernetesServiceConnection, Outpost, ServiceConnectionInvalid
|
||||
|
||||
|
||||
class KubernetesController(BaseController):
|
||||
@ -40,7 +41,7 @@ class KubernetesController(BaseController):
|
||||
reconciler = self.reconcilers[reconcile_key](self)
|
||||
reconciler.up()
|
||||
|
||||
except ApiException as exc:
|
||||
except (OpenApiException, HTTPError, ServiceConnectionInvalid) as exc:
|
||||
raise ControllerException(str(exc)) from exc
|
||||
|
||||
def up_with_logs(self) -> list[str]:
|
||||
@ -55,7 +56,7 @@ class KubernetesController(BaseController):
|
||||
reconciler.up()
|
||||
all_logs += [f"{reconcile_key.title()}: {x['event']}" for x in logs]
|
||||
return all_logs
|
||||
except ApiException as exc:
|
||||
except (OpenApiException, HTTPError, ServiceConnectionInvalid) as exc:
|
||||
raise ControllerException(str(exc)) from exc
|
||||
|
||||
def down(self):
|
||||
@ -65,7 +66,7 @@ class KubernetesController(BaseController):
|
||||
self.logger.debug("Tearing down object", name=reconcile_key)
|
||||
reconciler.down()
|
||||
|
||||
except ApiException as exc:
|
||||
except (OpenApiException, HTTPError, ServiceConnectionInvalid) as exc:
|
||||
raise ControllerException(str(exc)) from exc
|
||||
|
||||
def down_with_logs(self) -> list[str]:
|
||||
@ -80,7 +81,7 @@ class KubernetesController(BaseController):
|
||||
reconciler.down()
|
||||
all_logs += [f"{reconcile_key.title()}: {x['event']}" for x in logs]
|
||||
return all_logs
|
||||
except ApiException as exc:
|
||||
except (OpenApiException, HTTPError, ServiceConnectionInvalid) as exc:
|
||||
raise ControllerException(str(exc)) from exc
|
||||
|
||||
def get_static_deployment(self) -> str:
|
||||
|
@ -56,6 +56,7 @@ class ServiceConnectionInvalid(SentryIgnoredException):
|
||||
|
||||
|
||||
@dataclass
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
class OutpostConfig:
|
||||
"""Configuration an outpost uses to configure it self"""
|
||||
|
||||
@ -67,8 +68,10 @@ class OutpostConfig:
|
||||
log_level: str = CONFIG.y("log_level")
|
||||
error_reporting_enabled: bool = CONFIG.y_bool("error_reporting.enabled")
|
||||
error_reporting_environment: str = CONFIG.y("error_reporting.environment", "customer")
|
||||
|
||||
object_naming_template: str = field(default="ak-outpost-%(name)s")
|
||||
|
||||
docker_network: Optional[str] = field(default=None)
|
||||
|
||||
kubernetes_replicas: int = field(default=1)
|
||||
kubernetes_namespace: str = field(default_factory=get_namespace)
|
||||
kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
|
||||
@ -362,7 +365,7 @@ class Outpost(ManagedModel):
|
||||
)
|
||||
try:
|
||||
assign_perm(code_name, user, model_or_perm)
|
||||
except Permission.DoesNotExist as exc:
|
||||
except (Permission.DoesNotExist, AttributeError) as exc:
|
||||
LOGGER.warning(
|
||||
"permission doesn't exist",
|
||||
code_name=code_name,
|
||||
|
@ -8,8 +8,11 @@ from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.policies.models import Policy
|
||||
from authentik.policies.types import PolicyRequest, PolicyResult
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
|
||||
LOGGER = get_logger()
|
||||
RE_LOWER = re.compile("[a-z]")
|
||||
RE_UPPER = re.compile("[A-Z]")
|
||||
|
||||
|
||||
class PasswordPolicy(Policy):
|
||||
@ -38,31 +41,39 @@ class PasswordPolicy(Policy):
|
||||
return "ak-policy-password-form"
|
||||
|
||||
def passes(self, request: PolicyRequest) -> PolicyResult:
|
||||
if self.password_field not in request.context:
|
||||
if (
|
||||
self.password_field not in request.context
|
||||
and self.password_field not in request.context.get(PLAN_CONTEXT_PROMPT, {})
|
||||
):
|
||||
LOGGER.warning(
|
||||
"Password field not set in Policy Request",
|
||||
field=self.password_field,
|
||||
fields=request.context.keys(),
|
||||
prompt_fields=request.context.get(PLAN_CONTEXT_PROMPT, {}).keys(),
|
||||
)
|
||||
return PolicyResult(False, _("Password not set in context"))
|
||||
password = request.context[self.password_field]
|
||||
|
||||
filter_regex = []
|
||||
if self.amount_lowercase > 0:
|
||||
filter_regex.append(r"[a-z]{%d,}" % self.amount_lowercase)
|
||||
if self.amount_uppercase > 0:
|
||||
filter_regex.append(r"[A-Z]{%d,}" % self.amount_uppercase)
|
||||
if self.amount_symbols > 0:
|
||||
filter_regex.append(r"[%s]{%d,}" % (self.symbol_charset, self.amount_symbols))
|
||||
full_regex = "|".join(filter_regex)
|
||||
LOGGER.debug("Built regex", regexp=full_regex)
|
||||
result = bool(re.compile(full_regex).match(password))
|
||||
if self.password_field in request.context:
|
||||
password = request.context[self.password_field]
|
||||
else:
|
||||
password = request.context[PLAN_CONTEXT_PROMPT][self.password_field]
|
||||
|
||||
result = result and len(password) >= self.length_min
|
||||
if len(password) < self.length_min:
|
||||
LOGGER.debug("password failed", reason="length", p=password)
|
||||
return PolicyResult(False, self.error_message)
|
||||
|
||||
if not result:
|
||||
return PolicyResult(result, self.error_message)
|
||||
return PolicyResult(result)
|
||||
if self.amount_lowercase > 0 and len(RE_LOWER.findall(password)) < self.amount_lowercase:
|
||||
LOGGER.debug("password failed", reason="amount_lowercase", p=password)
|
||||
return PolicyResult(False, self.error_message)
|
||||
if self.amount_uppercase > 0 and len(RE_UPPER.findall(password)) < self.amount_lowercase:
|
||||
LOGGER.debug("password failed", reason="amount_uppercase", p=password)
|
||||
return PolicyResult(False, self.error_message)
|
||||
regex = re.compile(r"[%s]" % self.symbol_charset)
|
||||
if self.amount_symbols > 0 and len(regex.findall(password)) < self.amount_symbols:
|
||||
LOGGER.debug("password failed", reason="amount_symbols", p=password)
|
||||
return PolicyResult(False, self.error_message)
|
||||
|
||||
return PolicyResult(True)
|
||||
|
||||
class Meta:
|
||||
|
||||
|
@ -1,57 +0,0 @@
|
||||
"""Password Policy tests"""
|
||||
from django.test import TestCase
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
|
||||
from authentik.policies.password.models import PasswordPolicy
|
||||
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(
|
||||
name="test_false",
|
||||
amount_uppercase=1,
|
||||
amount_lowercase=2,
|
||||
amount_symbols=3,
|
||||
length_min=24,
|
||||
error_message="test message",
|
||||
)
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = "test"
|
||||
result: PolicyResult = policy.passes(request)
|
||||
self.assertFalse(result.passing)
|
||||
self.assertEqual(result.messages, ("test message",))
|
||||
|
||||
def test_true(self):
|
||||
"""Positive password case"""
|
||||
policy = PasswordPolicy.objects.create(
|
||||
name="test_true",
|
||||
amount_uppercase=1,
|
||||
amount_lowercase=2,
|
||||
amount_symbols=3,
|
||||
length_min=3,
|
||||
error_message="test message",
|
||||
)
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = "Test()!"
|
||||
result: PolicyResult = policy.passes(request)
|
||||
self.assertTrue(result.passing)
|
||||
self.assertEqual(result.messages, tuple())
|
0
authentik/policies/password/tests/__init__.py
Normal file
0
authentik/policies/password/tests/__init__.py
Normal file
80
authentik/policies/password/tests/test_flows.py
Normal file
80
authentik/policies/password/tests/test_flows.py
Normal file
@ -0,0 +1,80 @@
|
||||
"""Password flow tests"""
|
||||
from django.urls.base import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
|
||||
from authentik.policies.password.models import PasswordPolicy
|
||||
from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
|
||||
|
||||
|
||||
class TestPasswordPolicyFlow(APITestCase):
|
||||
"""Test Password Policy"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-prompt",
|
||||
slug="test-prompt",
|
||||
designation=FlowDesignation.AUTHENTICATION,
|
||||
)
|
||||
password_prompt = Prompt.objects.create(
|
||||
field_key="password",
|
||||
label="PASSWORD_LABEL",
|
||||
type=FieldTypes.PASSWORD,
|
||||
required=True,
|
||||
placeholder="PASSWORD_PLACEHOLDER",
|
||||
)
|
||||
|
||||
self.policy = PasswordPolicy.objects.create(
|
||||
name="test_true",
|
||||
amount_uppercase=1,
|
||||
amount_lowercase=2,
|
||||
amount_symbols=3,
|
||||
length_min=3,
|
||||
error_message="test message",
|
||||
)
|
||||
stage = PromptStage.objects.create(name="prompt-stage")
|
||||
stage.validation_policies.set([self.policy])
|
||||
stage.fields.set(
|
||||
[
|
||||
password_prompt,
|
||||
]
|
||||
)
|
||||
FlowStageBinding.objects.create(target=self.flow, stage=stage, order=2)
|
||||
|
||||
def test_prompt_data(self):
|
||||
"""Test policy attached to a prompt stage"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||
{"password": "akadmin"},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertJSONEqual(
|
||||
force_str(response.content),
|
||||
{
|
||||
"component": "ak-stage-prompt",
|
||||
"fields": [
|
||||
{
|
||||
"field_key": "password",
|
||||
"label": "PASSWORD_LABEL",
|
||||
"order": 0,
|
||||
"placeholder": "PASSWORD_PLACEHOLDER",
|
||||
"required": True,
|
||||
"type": "password",
|
||||
}
|
||||
],
|
||||
"flow_info": {
|
||||
"background": self.flow.background_url,
|
||||
"cancel_url": reverse("authentik_flows:cancel"),
|
||||
"title": "",
|
||||
},
|
||||
"response_errors": {
|
||||
"non_field_errors": [{"code": "invalid", "string": self.policy.error_message}]
|
||||
},
|
||||
"type": ChallengeTypes.NATIVE.value,
|
||||
},
|
||||
)
|
68
authentik/policies/password/tests/test_policy.py
Normal file
68
authentik/policies/password/tests/test_policy.py
Normal file
@ -0,0 +1,68 @@
|
||||
"""Password Policy tests"""
|
||||
from django.test import TestCase
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
|
||||
from authentik.lib.generators import generate_key
|
||||
from authentik.policies.password.models import PasswordPolicy
|
||||
from authentik.policies.types import PolicyRequest, PolicyResult
|
||||
|
||||
|
||||
class TestPasswordPolicy(TestCase):
|
||||
"""Test Password Policy"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.policy = PasswordPolicy.objects.create(
|
||||
name="test_false",
|
||||
amount_uppercase=1,
|
||||
amount_lowercase=2,
|
||||
amount_symbols=3,
|
||||
length_min=24,
|
||||
error_message="test message",
|
||||
)
|
||||
|
||||
def test_invalid(self):
|
||||
"""Test without password"""
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
result: PolicyResult = self.policy.passes(request)
|
||||
self.assertFalse(result.passing)
|
||||
self.assertEqual(result.messages[0], "Password not set in context")
|
||||
|
||||
def test_failed_length(self):
|
||||
"""Password too short"""
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = "test"
|
||||
result: PolicyResult = self.policy.passes(request)
|
||||
self.assertFalse(result.passing)
|
||||
self.assertEqual(result.messages, ("test message",))
|
||||
|
||||
def test_failed_lowercase(self):
|
||||
"""not enough lowercase"""
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = "TTTTTTTTTTTTTTTTTTTTTTTe"
|
||||
result: PolicyResult = self.policy.passes(request)
|
||||
self.assertFalse(result.passing)
|
||||
self.assertEqual(result.messages, ("test message",))
|
||||
|
||||
def test_failed_uppercase(self):
|
||||
"""not enough uppercase"""
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = "tttttttttttttttttttttttE"
|
||||
result: PolicyResult = self.policy.passes(request)
|
||||
self.assertFalse(result.passing)
|
||||
self.assertEqual(result.messages, ("test message",))
|
||||
|
||||
def test_failed_symbols(self):
|
||||
"""not enough uppercase"""
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = "TETETETETETETETETETETETETe!!!"
|
||||
result: PolicyResult = self.policy.passes(request)
|
||||
self.assertFalse(result.passing)
|
||||
self.assertEqual(result.messages, ("test message",))
|
||||
|
||||
def test_true(self):
|
||||
"""Positive password case"""
|
||||
request = PolicyRequest(get_anonymous_user())
|
||||
request.context["password"] = generate_key() + "ee!!!"
|
||||
result: PolicyResult = self.policy.passes(request)
|
||||
self.assertTrue(result.passing)
|
||||
self.assertEqual(result.messages, tuple())
|
@ -3,7 +3,7 @@ from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
@ -49,12 +49,12 @@ class OAuth2ProviderSerializer(ProviderSerializer):
|
||||
class OAuth2ProviderSetupURLs(PassiveSerializer):
|
||||
"""OAuth2 Provider Metadata serializer"""
|
||||
|
||||
issuer = ReadOnlyField()
|
||||
authorize = ReadOnlyField()
|
||||
token = ReadOnlyField()
|
||||
user_info = ReadOnlyField()
|
||||
provider_info = ReadOnlyField()
|
||||
logout = ReadOnlyField()
|
||||
issuer = CharField(read_only=True)
|
||||
authorize = CharField(read_only=True)
|
||||
token = CharField(read_only=True)
|
||||
user_info = CharField(read_only=True)
|
||||
provider_info = CharField(read_only=True)
|
||||
logout = CharField(read_only=True)
|
||||
|
||||
|
||||
class OAuth2ProviderViewSet(UsedByMixin, ModelViewSet):
|
||||
|
@ -22,13 +22,13 @@ class ProxyDockerController(DockerController):
|
||||
for proxy_provider in ProxyProvider.objects.filter(outpost__in=[self.outpost]):
|
||||
proxy_provider: ProxyProvider
|
||||
external_host_name = urlparse(proxy_provider.external_host)
|
||||
hosts.append(f"`{external_host_name}`")
|
||||
hosts.append(f"`{external_host_name.netloc}`")
|
||||
traefik_name = f"ak-outpost-{self.outpost.pk.hex}"
|
||||
return {
|
||||
"traefik.enable": "true",
|
||||
f"traefik.http.routers.{traefik_name}-router.rule": f"Host({','.join(hosts)})",
|
||||
f"traefik.http.routers.{traefik_name}-router.tls": "true",
|
||||
f"traefik.http.routers.{traefik_name}-router.service": f"{traefik_name}-service",
|
||||
f"traefik.http.services.{traefik_name}-service.loadbalancer.healthcheck.path": "/",
|
||||
f"traefik.http.services.{traefik_name}-service.loadbalancer.server.port": "4180",
|
||||
}
|
||||
labels = super()._get_labels()
|
||||
labels["traefik.enable"] = "true"
|
||||
labels[f"traefik.http.routers.{traefik_name}-router.rule"] = f"Host({','.join(hosts)})"
|
||||
labels[f"traefik.http.routers.{traefik_name}-router.tls"] = "true"
|
||||
labels[f"traefik.http.routers.{traefik_name}-router.service"] = f"{traefik_name}-service"
|
||||
labels[f"traefik.http.services.{traefik_name}-service.loadbalancer.healthcheck.path"] = "/"
|
||||
labels[f"traefik.http.services.{traefik_name}-service.loadbalancer.server.port"] = "4180"
|
||||
return labels
|
||||
|
@ -61,9 +61,10 @@ class IngressReconciler(KubernetesObjectReconciler[NetworkingV1beta1Ingress]):
|
||||
have_hosts.sort()
|
||||
|
||||
have_hosts_tls = []
|
||||
for tls_config in current.spec.tls:
|
||||
if tls_config and tls_config.hosts:
|
||||
have_hosts_tls += tls_config.hosts
|
||||
if current.spec.tls:
|
||||
for tls_config in current.spec.tls:
|
||||
if tls_config and tls_config.hosts:
|
||||
have_hosts_tls += tls_config.hosts
|
||||
have_hosts_tls.sort()
|
||||
|
||||
if have_hosts != expected_hosts:
|
||||
|
@ -96,6 +96,7 @@ class TraefikMiddlewareReconciler(KubernetesObjectReconciler[TraefikMiddleware])
|
||||
|
||||
def get_reference_object(self) -> TraefikMiddleware:
|
||||
"""Get deployment object for outpost"""
|
||||
port = 9000 if self.is_embedded else 4180
|
||||
return TraefikMiddleware(
|
||||
apiVersion=f"{CRD_GROUP}/{CRD_VERSION}",
|
||||
kind="Middleware",
|
||||
@ -106,7 +107,7 @@ class TraefikMiddlewareReconciler(KubernetesObjectReconciler[TraefikMiddleware])
|
||||
),
|
||||
spec=TraefikMiddlewareSpec(
|
||||
forwardAuth=TraefikMiddlewareSpecForwardAuth(
|
||||
address=f"http://{self.name}.{self.namespace}:4180/akprox/auth?traefik",
|
||||
address=f"http://{self.name}.{self.namespace}:{port}/akprox/auth?traefik",
|
||||
authResponseHeaders=[
|
||||
"Set-Cookie",
|
||||
"X-Auth-Username",
|
||||
|
@ -11,7 +11,7 @@ from django_filters.filterset import FilterSet
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, FileField, ReadOnlyField, SerializerMethodField
|
||||
from rest_framework.fields import CharField, FileField, SerializerMethodField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.relations import SlugRelatedField
|
||||
@ -70,8 +70,8 @@ class SAMLProviderSerializer(ProviderSerializer):
|
||||
class SAMLMetadataSerializer(PassiveSerializer):
|
||||
"""SAML Provider Metadata serializer"""
|
||||
|
||||
metadata = ReadOnlyField()
|
||||
download_url = ReadOnlyField(required=False)
|
||||
metadata = CharField(read_only=True)
|
||||
download_url = CharField(read_only=True, required=False)
|
||||
|
||||
|
||||
class SAMLProviderImportSerializer(PassiveSerializer):
|
||||
|
@ -33,7 +33,6 @@ class ASGIErrorHandler:
|
||||
)
|
||||
return await send(
|
||||
{
|
||||
"type": "websocket.send",
|
||||
"text": b"Internal server error",
|
||||
"type": "websocket.close",
|
||||
}
|
||||
)
|
||||
|
@ -74,6 +74,7 @@ LANGUAGE_COOKIE_NAME = f"authentik_language{_cookie_suffix}"
|
||||
SESSION_COOKIE_NAME = f"authentik_session{_cookie_suffix}"
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
BACKEND_INBUILT,
|
||||
BACKEND_APP_PASSWORD,
|
||||
BACKEND_LDAP,
|
||||
@ -149,9 +150,20 @@ SPECTACULAR_SETTINGS = {
|
||||
"DESCRIPTION": "Making authentication simple.",
|
||||
"VERSION": __version__,
|
||||
"COMPONENT_SPLIT_REQUEST": True,
|
||||
"SCHEMA_PATH_PREFIX": "/api/v([0-9]+(beta)?)",
|
||||
"SCHEMA_PATH_PREFIX_TRIM": True,
|
||||
"SERVERS": [
|
||||
{
|
||||
"url": "http://authentik.tld/api/v3/",
|
||||
},
|
||||
{
|
||||
"url": "http://authentik.tld/api/v2beta/",
|
||||
},
|
||||
],
|
||||
"CONTACT": {
|
||||
"email": "hello@beryju.org",
|
||||
},
|
||||
"AUTHENTICATION_WHITELIST": ["authentik.api.authentication.TokenAuthentication"],
|
||||
"LICENSE": {
|
||||
"name": "GNU GPLv3",
|
||||
"url": "https://github.com/goauthentik/authentik/blob/master/LICENSE",
|
||||
@ -179,6 +191,9 @@ REST_FRAMEWORK = {
|
||||
"rest_framework.filters.OrderingFilter",
|
||||
"rest_framework.filters.SearchFilter",
|
||||
],
|
||||
"DEFAULT_PARSER_CLASSES": [
|
||||
"rest_framework.parsers.JSONParser",
|
||||
],
|
||||
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.DjangoObjectPermissions",),
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"authentik.api.authentication.TokenAuthentication",
|
||||
@ -188,6 +203,7 @@ REST_FRAMEWORK = {
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
],
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
"TEST_REQUEST_DEFAULT_FORMAT": "json",
|
||||
}
|
||||
|
||||
REDIS_PROTOCOL_PREFIX = "redis://"
|
||||
@ -371,6 +387,7 @@ if CONFIG.y("postgresql.s3_backup"):
|
||||
"default_acl": "private",
|
||||
"endpoint_url": CONFIG.y("postgresql.s3_backup.host"),
|
||||
"location": CONFIG.y("postgresql.s3_backup.location", ""),
|
||||
"verify": not CONFIG.y_bool("postgresql.s3_backup.insecure_skip_verify", False),
|
||||
}
|
||||
j_print(
|
||||
"Database backup to S3 is configured",
|
||||
|
@ -2,17 +2,13 @@
|
||||
from base64 import b64encode
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import Client, TestCase
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class TestRoot(TestCase):
|
||||
"""Test root application"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.client = Client()
|
||||
|
||||
def test_monitoring_error(self):
|
||||
"""Test monitoring without any credentials"""
|
||||
response = self.client.get(reverse("metrics"))
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""Twitter Type tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.test import TestCase
|
||||
|
||||
from authentik.sources.oauth.models import OAuthSource
|
||||
from authentik.sources.oauth.types.twitter import TwitterOAuthCallback
|
||||
@ -92,7 +92,6 @@ class TestTypeGitHub(TestCase):
|
||||
"""OAuth Source tests"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
self.source = OAuthSource.objects.create(
|
||||
name="test",
|
||||
slug="test",
|
||||
|
@ -51,20 +51,30 @@ def get_webauthn_challenge(request: HttpRequest, device: WebAuthnDevice) -> dict
|
||||
# for the reasons outlined in the comment in webauthn_begin_activate.
|
||||
request.session["challenge"] = challenge.rstrip("=")
|
||||
|
||||
webauthn_user = WebAuthnUser(
|
||||
device.user.uid,
|
||||
device.user.username,
|
||||
device.user.name,
|
||||
device.user.avatar,
|
||||
device.credential_id,
|
||||
device.public_key,
|
||||
device.sign_count,
|
||||
device.rp_id,
|
||||
)
|
||||
assertion = {}
|
||||
user = device.user
|
||||
|
||||
webauthn_assertion_options = WebAuthnAssertionOptions(webauthn_user, challenge)
|
||||
# We want all the user's WebAuthn devices and merge their challenges
|
||||
for user_device in WebAuthnDevice.objects.filter(user=device.user).order_by("name"):
|
||||
webauthn_user = WebAuthnUser(
|
||||
user.uid,
|
||||
user.username,
|
||||
user.name,
|
||||
user.avatar,
|
||||
user_device.credential_id,
|
||||
user_device.public_key,
|
||||
user_device.sign_count,
|
||||
user_device.rp_id,
|
||||
)
|
||||
webauthn_assertion_options = WebAuthnAssertionOptions(webauthn_user, challenge)
|
||||
if assertion == {}:
|
||||
assertion = webauthn_assertion_options.assertion_dict
|
||||
else:
|
||||
assertion["allowCredentials"] += webauthn_assertion_options.assertion_dict.get(
|
||||
"allowCredentials"
|
||||
)
|
||||
|
||||
return webauthn_assertion_options.assertion_dict
|
||||
return assertion
|
||||
|
||||
|
||||
def validate_challenge_code(code: str, request: HttpRequest, user: User) -> str:
|
||||
|
@ -20,8 +20,6 @@ from authentik.stages.authenticator_validate.models import AuthenticatorValidate
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
PER_DEVICE_CLASSES = [DeviceClasses.WEBAUTHN]
|
||||
|
||||
|
||||
class AuthenticatorValidationChallenge(WithUserInfoChallenge):
|
||||
"""Authenticator challenge"""
|
||||
@ -91,9 +89,9 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
||||
if device_class not in stage.device_classes:
|
||||
LOGGER.debug("device class not allowed", device_class=device_class)
|
||||
continue
|
||||
# Ensure only classes in PER_DEVICE_CLASSES are returned per device
|
||||
# otherwise only return a single challenge
|
||||
if device_class in seen_classes and device_class not in PER_DEVICE_CLASSES:
|
||||
# Ensure only one challenge per device class
|
||||
# WebAuthn does another device loop to find all webuahtn devices
|
||||
if device_class in seen_classes:
|
||||
continue
|
||||
if device_class not in seen_classes:
|
||||
seen_classes.append(device_class)
|
||||
|
@ -1,12 +1,12 @@
|
||||
"""Test validator stage"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls.base import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -26,7 +26,7 @@ from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||
from authentik.stages.identification.models import IdentificationStage, UserFields
|
||||
|
||||
|
||||
class AuthenticatorValidateStageTests(TestCase):
|
||||
class AuthenticatorValidateStageTests(APITestCase):
|
||||
"""Test validator stage"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""captcha tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -16,13 +16,12 @@ RECAPTCHA_PUBLIC_KEY = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
|
||||
RECAPTCHA_PRIVATE_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
|
||||
|
||||
|
||||
class TestCaptchaStage(TestCase):
|
||||
class TestCaptchaStage(APITestCase):
|
||||
"""Captcha tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_user(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-captcha",
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""consent tests"""
|
||||
from time import sleep
|
||||
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import Application, User
|
||||
from authentik.core.tasks import clean_expired_models
|
||||
@ -15,7 +15,7 @@ from authentik.flows.views import SESSION_KEY_PLAN
|
||||
from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent
|
||||
|
||||
|
||||
class TestConsentStage(TestCase):
|
||||
class TestConsentStage(APITestCase):
|
||||
"""Consent tests"""
|
||||
|
||||
def setUp(self):
|
||||
@ -25,7 +25,6 @@ class TestConsentStage(TestCase):
|
||||
name="test-application",
|
||||
slug="test-application",
|
||||
)
|
||||
self.client = Client()
|
||||
|
||||
def test_always_required(self):
|
||||
"""Test always required consent"""
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""deny tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -12,13 +12,12 @@ from authentik.flows.views import SESSION_KEY_PLAN
|
||||
from authentik.stages.deny.models import DenyStage
|
||||
|
||||
|
||||
class TestUserDenyStage(TestCase):
|
||||
class TestUserDenyStage(APITestCase):
|
||||
"""Deny tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-logout",
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""dummy tests"""
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -9,7 +9,7 @@ from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
|
||||
from authentik.stages.dummy.models import DummyStage
|
||||
|
||||
|
||||
class TestDummyStage(TestCase):
|
||||
class TestDummyStage(APITestCase):
|
||||
"""Dummy tests"""
|
||||
|
||||
def setUp(self):
|
||||
|
@ -4,8 +4,8 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.core import mail
|
||||
from django.core.mail.backends.locmem import EmailBackend
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event, EventAction
|
||||
@ -16,13 +16,12 @@ from authentik.flows.views import SESSION_KEY_PLAN
|
||||
from authentik.stages.email.models import EmailStage
|
||||
|
||||
|
||||
class TestEmailStageSending(TestCase):
|
||||
class TestEmailStageSending(APITestCase):
|
||||
"""Email tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_user(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-email",
|
||||
|
@ -2,10 +2,10 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.core import mail
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.http import urlencode
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import Token, User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -17,13 +17,12 @@ from authentik.stages.email.models import EmailStage
|
||||
from authentik.stages.email.stage import QS_KEY_TOKEN
|
||||
|
||||
|
||||
class TestEmailStage(TestCase):
|
||||
class TestEmailStage(APITestCase):
|
||||
"""Email tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_user(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-email",
|
||||
|
@ -96,7 +96,9 @@ class IdentificationChallengeResponse(ChallengeResponse):
|
||||
# No password stage select, don't validate the password
|
||||
return attrs
|
||||
|
||||
password = attrs["password"]
|
||||
password = attrs.get("password", None)
|
||||
if not password:
|
||||
LOGGER.warning("Password not set for ident+auth attempt")
|
||||
try:
|
||||
user = authenticate(
|
||||
self.stage.request,
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""identification tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -13,7 +13,7 @@ from authentik.stages.password import BACKEND_INBUILT
|
||||
from authentik.stages.password.models import PasswordStage
|
||||
|
||||
|
||||
class TestIdentificationStage(TestCase):
|
||||
class TestIdentificationStage(APITestCase):
|
||||
"""Identification tests"""
|
||||
|
||||
def setUp(self):
|
||||
@ -22,7 +22,6 @@ class TestIdentificationStage(TestCase):
|
||||
self.user = User.objects.create_user(
|
||||
username="unittest", email="test@beryju.org", password=self.password
|
||||
)
|
||||
self.client = Client()
|
||||
|
||||
# OAuthSource for the login view
|
||||
source = OAuthSource.objects.create(name="test", slug="test")
|
||||
|
@ -0,0 +1,25 @@
|
||||
# Generated by Django 3.2.6 on 2021-09-01 12:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import authentik.core.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_invitation", "0004_invitation_single_use"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="invitation",
|
||||
name="expiring",
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="invitation",
|
||||
name="expires",
|
||||
field=models.DateTimeField(default=authentik.core.models.default_token_duration),
|
||||
),
|
||||
]
|
@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.core.models import ExpiringModel, User
|
||||
from authentik.flows.models import Stage
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ class InvitationStage(Stage):
|
||||
verbose_name_plural = _("Invitation Stages")
|
||||
|
||||
|
||||
class Invitation(models.Model):
|
||||
class Invitation(ExpiringModel):
|
||||
"""Single-use invitation link"""
|
||||
|
||||
invite_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||
@ -59,7 +59,6 @@ class Invitation(models.Model):
|
||||
)
|
||||
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
expires = models.DateTimeField(default=None, blank=True, null=True)
|
||||
fixed_data = models.JSONField(
|
||||
default=dict,
|
||||
blank=True,
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""invitation tests"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.http import urlencode
|
||||
@ -21,13 +20,12 @@ from authentik.stages.password import BACKEND_INBUILT
|
||||
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||
|
||||
|
||||
class TestUserLoginStage(TestCase):
|
||||
class TestUserLoginStage(APITestCase):
|
||||
"""Login tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-invitation",
|
||||
|
@ -32,9 +32,7 @@ PLAN_CONTEXT_METHOD_ARGS = "auth_method_args"
|
||||
SESSION_INVALID_TRIES = "user_invalid_tries"
|
||||
|
||||
|
||||
def authenticate(
|
||||
request: HttpRequest, backends: list[str], **credentials: dict[str, Any]
|
||||
) -> Optional[User]:
|
||||
def authenticate(request: HttpRequest, backends: list[str], **credentials: Any) -> Optional[User]:
|
||||
"""If the given credentials are valid, return a User object.
|
||||
|
||||
Customized version of django's authenticate, which accepts a list of backends"""
|
||||
|
@ -2,9 +2,9 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -20,7 +20,7 @@ from authentik.stages.password.models import PasswordStage
|
||||
MOCK_BACKEND_AUTHENTICATE = MagicMock(side_effect=PermissionDenied("test"))
|
||||
|
||||
|
||||
class TestPasswordStage(TestCase):
|
||||
class TestPasswordStage(APITestCase):
|
||||
"""Password tests"""
|
||||
|
||||
def setUp(self):
|
||||
@ -29,7 +29,6 @@ class TestPasswordStage(TestCase):
|
||||
self.user = User.objects.create_user(
|
||||
username="unittest", email="test@beryju.org", password=self.password
|
||||
)
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-password",
|
||||
|
@ -1,10 +1,10 @@
|
||||
"""Prompt tests"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.exceptions import ErrorDetail
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -17,13 +17,12 @@ from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT, PromptChallengeResponse
|
||||
|
||||
|
||||
class TestPromptStage(TestCase):
|
||||
class TestPromptStage(APITestCase):
|
||||
"""Prompt tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-prompt",
|
||||
@ -97,7 +96,6 @@ class TestPromptStage(TestCase):
|
||||
static_prompt,
|
||||
]
|
||||
)
|
||||
self.stage.save()
|
||||
|
||||
self.prompt_data = {
|
||||
username_prompt.field_key: "test-username",
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""delete tests"""
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -15,14 +15,13 @@ from authentik.flows.views import SESSION_KEY_PLAN
|
||||
from authentik.stages.user_delete.models import UserDeleteStage
|
||||
|
||||
|
||||
class TestUserDeleteStage(TestCase):
|
||||
class TestUserDeleteStage(APITestCase):
|
||||
"""Delete tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.username = "qerqwerqrwqwerwq"
|
||||
self.user = User.objects.create(username=self.username, email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-delete",
|
||||
|
@ -2,9 +2,9 @@
|
||||
from time import sleep
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -16,13 +16,12 @@ from authentik.flows.views import SESSION_KEY_PLAN
|
||||
from authentik.stages.user_login.models import UserLoginStage
|
||||
|
||||
|
||||
class TestUserLoginStage(TestCase):
|
||||
class TestUserLoginStage(APITestCase):
|
||||
"""Login tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-login",
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""logout tests"""
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.flows.challenge import ChallengeTypes
|
||||
@ -14,13 +14,12 @@ from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||
from authentik.stages.user_logout.models import UserLogoutStage
|
||||
|
||||
|
||||
class TestUserLogoutStage(TestCase):
|
||||
class TestUserLogoutStage(APITestCase):
|
||||
"""Logout tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-logout",
|
||||
|
@ -3,9 +3,9 @@ import string
|
||||
from random import SystemRandom
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.models import USER_ATTRIBUTE_SOURCES, Source, User, UserSourceConnection
|
||||
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
||||
@ -19,13 +19,11 @@ from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
from authentik.stages.user_write.models import UserWriteStage
|
||||
|
||||
|
||||
class TestUserWriteStage(TestCase):
|
||||
class TestUserWriteStage(APITestCase):
|
||||
"""Write tests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.client = Client()
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-write",
|
||||
slug="test-write",
|
||||
|
@ -1,120 +0,0 @@
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- next
|
||||
- version-*
|
||||
|
||||
stages:
|
||||
- stage: generate
|
||||
jobs:
|
||||
- job: generate_api
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
inputs:
|
||||
version: '1.16.3'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: make gen-outpost
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'api/'
|
||||
artifact: 'go_api_client'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: lint
|
||||
jobs:
|
||||
- job: golint
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
inputs:
|
||||
version: '1.16.3'
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'go_api_client'
|
||||
path: "api/"
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
mkdir -p web/dist
|
||||
mkdir -p website/help
|
||||
touch web/dist/test website/help/test
|
||||
docker run \
|
||||
--rm \
|
||||
-v $(pwd):/app \
|
||||
-w /app \
|
||||
golangci/golangci-lint:v1.39.0 \
|
||||
golangci-lint run -v --timeout 200s
|
||||
- stage: build_docker
|
||||
jobs:
|
||||
- job: proxy_build_docker
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
inputs:
|
||||
version: '1.16.3'
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
python ./scripts/az_do_set_branch.py
|
||||
- task: Docker@2
|
||||
inputs:
|
||||
containerRegistry: 'beryjuorg-harbor'
|
||||
repository: 'authentik/outpost-proxy'
|
||||
command: 'build'
|
||||
Dockerfile: 'proxy.Dockerfile'
|
||||
buildContext: '$(Build.SourcesDirectory)'
|
||||
tags: |
|
||||
gh-$(branchName)
|
||||
gh-$(branchName)-$(timestamp)
|
||||
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-$(branchName)-$(timestamp)
|
||||
gh-$(Build.SourceVersion)
|
||||
- job: ldap_build_docker
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
inputs:
|
||||
version: '1.16.3'
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
python ./scripts/az_do_set_branch.py
|
||||
- task: Docker@2
|
||||
inputs:
|
||||
containerRegistry: 'beryjuorg-harbor'
|
||||
repository: 'authentik/outpost-ldap'
|
||||
command: 'build'
|
||||
Dockerfile: 'ldap.Dockerfile'
|
||||
buildContext: '$(Build.SourcesDirectory)'
|
||||
tags: |
|
||||
gh-$(branchName)
|
||||
gh-$(branchName)-$(timestamp)
|
||||
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-$(branchName)-$(timestamp)
|
||||
gh-$(Build.SourceVersion)
|
@ -1,426 +0,0 @@
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- next
|
||||
- version-*
|
||||
paths:
|
||||
exclude:
|
||||
- website
|
||||
- outpost
|
||||
|
||||
resources:
|
||||
- repo: self
|
||||
|
||||
variables:
|
||||
- name: POSTGRES_DB
|
||||
value: authentik
|
||||
- name: POSTGRES_USER
|
||||
value: authentik
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "EK-5jnKfjrGRm<77"
|
||||
- group: coverage
|
||||
|
||||
stages:
|
||||
- stage: Lint_and_test
|
||||
jobs:
|
||||
- job: pylint
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: DockerCompose@0
|
||||
displayName: Run services
|
||||
inputs:
|
||||
dockerComposeFile: 'scripts/ci.docker-compose.yml'
|
||||
action: 'Run services'
|
||||
buildImages: false
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run pylint authentik tests lifecycle
|
||||
- job: black
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run black --check authentik tests lifecycle
|
||||
- job: isort
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run isort --check authentik tests lifecycle
|
||||
- job: bandit
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run bandit -r authentik tests lifecycle
|
||||
- job: pyright
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
steps:
|
||||
- task: UseNode@1
|
||||
inputs:
|
||||
version: '12.x'
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: npm install -g pyright@1.1.136
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: pipenv run pyright e2e lifecycle
|
||||
- job: migrations
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: DockerCompose@0
|
||||
displayName: Run services
|
||||
inputs:
|
||||
dockerComposeFile: 'scripts/ci.docker-compose.yml'
|
||||
action: 'Run services'
|
||||
buildImages: false
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run python -m lifecycle.migrate
|
||||
- job: migrations_from_previous_release
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.8'
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: DockerCompose@0
|
||||
displayName: Run services
|
||||
inputs:
|
||||
dockerComposeFile: 'scripts/ci.docker-compose.yml'
|
||||
action: 'Run services'
|
||||
buildImages: false
|
||||
- task: CmdLine@2
|
||||
displayName: Prepare Last tagged release
|
||||
inputs:
|
||||
script: |
|
||||
# Copy current, latest config to local
|
||||
cp authentik/lib/default.yml local.env.yml
|
||||
git checkout $(git describe --abbrev=0 --match 'version/*')
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
displayName: Migrate to last tagged release
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run python -m lifecycle.migrate
|
||||
- task: CmdLine@2
|
||||
displayName: Install current branch
|
||||
inputs:
|
||||
script: |
|
||||
set -x
|
||||
git checkout ${{ variables.branchName }}
|
||||
pipenv sync --dev
|
||||
- task: CmdLine@2
|
||||
displayName: Migrate to current branch
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run python -m lifecycle.migrate
|
||||
- job: coverage_unittest
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: DockerCompose@0
|
||||
displayName: Run services
|
||||
inputs:
|
||||
dockerComposeFile: 'scripts/ci.docker-compose.yml'
|
||||
action: 'Run services'
|
||||
buildImages: false
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
displayName: Run full test suite
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run make test
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
mkdir output-unittest
|
||||
mv unittest.xml output-unittest/unittest.xml
|
||||
mv .coverage output-unittest/coverage
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'output-unittest/'
|
||||
artifact: 'coverage-unittest'
|
||||
publishLocation: 'pipeline'
|
||||
- job: coverage_integration
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: DockerCompose@0
|
||||
displayName: Run services
|
||||
inputs:
|
||||
dockerComposeFile: 'scripts/ci.docker-compose.yml'
|
||||
action: 'Run services'
|
||||
buildImages: false
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
- task: CmdLine@2
|
||||
displayName: Install K3d and prepare
|
||||
inputs:
|
||||
script: |
|
||||
wget -q -O - https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash
|
||||
k3d cluster create
|
||||
k3d kubeconfig write -o ~/.kube/config --overwrite
|
||||
- task: CmdLine@2
|
||||
displayName: Run full test suite
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run make test-integration
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
mkdir output-integration
|
||||
mv unittest.xml output-integration/unittest.xml
|
||||
mv .coverage output-integration/coverage
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'output-integration/'
|
||||
artifact: 'coverage-integration'
|
||||
publishLocation: 'pipeline'
|
||||
- job: coverage_e2e
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
- task: DockerCompose@0
|
||||
displayName: Run services
|
||||
inputs:
|
||||
dockerComposeFile: 'scripts/ci.docker-compose.yml'
|
||||
action: 'Run services'
|
||||
buildImages: false
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev --python python3.9
|
||||
- task: DockerCompose@0
|
||||
displayName: Run ChromeDriver
|
||||
inputs:
|
||||
dockerComposeFile: 'tests/e2e/ci.docker-compose.yml'
|
||||
action: 'Run a specific service'
|
||||
serviceName: 'chrome'
|
||||
- task: CmdLine@2
|
||||
displayName: Build static files for e2e
|
||||
inputs:
|
||||
script: |
|
||||
cd web
|
||||
npm i
|
||||
npm run build
|
||||
- task: CmdLine@2
|
||||
displayName: Run full test suite
|
||||
inputs:
|
||||
script: |
|
||||
pipenv run python -m scripts.generate_ci_config
|
||||
pipenv run make test-e2e
|
||||
- task: CmdLine@2
|
||||
condition: always()
|
||||
displayName: Cleanup
|
||||
inputs:
|
||||
script: |
|
||||
docker stop $(docker ps -aq)
|
||||
docker container prune -f
|
||||
- task: CmdLine@2
|
||||
displayName: Prepare unittests and coverage for upload
|
||||
inputs:
|
||||
script: |
|
||||
mkdir output-e2e
|
||||
mv unittest.xml output-e2e/unittest.xml
|
||||
mv .coverage output-e2e/coverage
|
||||
- task: PublishPipelineArtifact@1
|
||||
condition: failed()
|
||||
displayName: Upload screenshots if selenium tests fail
|
||||
inputs:
|
||||
targetPath: 'selenium_screenshots/'
|
||||
artifact: 'selenium screenshots'
|
||||
publishLocation: 'pipeline'
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: 'output-e2e/'
|
||||
artifact: 'coverage-e2e'
|
||||
publishLocation: 'pipeline'
|
||||
- stage: test_combine
|
||||
jobs:
|
||||
- job: test_coverage_combine
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'coverage-e2e'
|
||||
path: "coverage-e2e/"
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'coverage-integration'
|
||||
path: "coverage-integration/"
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'current'
|
||||
artifactName: 'coverage-unittest'
|
||||
path: "coverage-unittest/"
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.9'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: |
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
pipenv run coverage combine coverage-e2e/coverage coverage-unittest/coverage coverage-integration/coverage
|
||||
pipenv run coverage xml
|
||||
pipenv run coverage html
|
||||
- task: PublishCodeCoverageResults@1
|
||||
inputs:
|
||||
codeCoverageTool: 'Cobertura'
|
||||
summaryFileLocation: 'coverage.xml'
|
||||
pathToSources: '$(System.DefaultWorkingDirectory)'
|
||||
- task: PublishTestResults@2
|
||||
condition: succeededOrFailed()
|
||||
inputs:
|
||||
testResultsFormat: 'JUnit'
|
||||
testResultsFiles: |
|
||||
coverage-e2e/unittest.xml
|
||||
coverage-integration/unittest.xml
|
||||
coverage-unittest/unittest.xml
|
||||
mergeTestResults: true
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: bash <(curl -s https://codecov.io/bash)
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: build_server
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: Bash@3
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
python ./scripts/az_do_set_branch.py
|
||||
- task: Docker@2
|
||||
inputs:
|
||||
containerRegistry: 'beryjuorg-harbor'
|
||||
repository: 'authentik/server'
|
||||
command: 'build'
|
||||
Dockerfile: 'Dockerfile'
|
||||
tags: |
|
||||
gh-$(branchName)
|
||||
gh-$(branchName)-$(timestamp)
|
||||
arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)'
|
||||
- task: Docker@2
|
||||
inputs:
|
||||
containerRegistry: 'beryjuorg-harbor'
|
||||
repository: 'authentik/server'
|
||||
command: 'push'
|
||||
tags: |
|
||||
gh-$(branchName)
|
||||
gh-$(branchName)-$(timestamp)
|
@ -60,7 +60,9 @@ func main() {
|
||||
for {
|
||||
go attemptStartBackend(g)
|
||||
ws.Start()
|
||||
go attemptProxyStart(ws, u)
|
||||
if !config.G.Web.DisableEmbeddedOutpost {
|
||||
go attemptProxyStart(ws, u)
|
||||
}
|
||||
|
||||
<-ex
|
||||
running = false
|
||||
|
@ -10,7 +10,7 @@ services:
|
||||
networks:
|
||||
- internal
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=${PG_PASS:-thisisnotagoodpassword}
|
||||
- POSTGRES_PASSWORD=${PG_PASS:?database password required}
|
||||
- POSTGRES_USER=${PG_USER:-authentik}
|
||||
- POSTGRES_DB=${PG_DB:-authentik}
|
||||
env_file:
|
||||
@ -21,7 +21,7 @@ services:
|
||||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.8.1-rc2}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.8.4}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -44,7 +44,7 @@ services:
|
||||
- "0.0.0.0:9000:9000"
|
||||
- "0.0.0.0:9443:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.8.1-rc2}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.8.4}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
networks:
|
||||
|
2
go.mod
2
go.mod
@ -10,7 +10,7 @@ require (
|
||||
github.com/go-ldap/ldap/v3 v3.4.1
|
||||
github.com/go-openapi/analysis v0.20.1 // indirect
|
||||
github.com/go-openapi/errors v0.20.0 // indirect
|
||||
github.com/go-openapi/runtime v0.19.30
|
||||
github.com/go-openapi/runtime v0.19.31
|
||||
github.com/go-openapi/strfmt v0.20.2
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/validate v0.20.2 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -205,8 +205,8 @@ github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29g
|
||||
github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=
|
||||
github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98=
|
||||
github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk=
|
||||
github.com/go-openapi/runtime v0.19.30 h1:bVDeSf4HU9EMth+lHD1EthaHe1SFoUVPaUvQtkGS9g8=
|
||||
github.com/go-openapi/runtime v0.19.30/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M=
|
||||
github.com/go-openapi/runtime v0.19.31 h1:GX+MgBxN12s/tQiHNJpvHDIoZiEXAz6j6Rqg0oJcnpg=
|
||||
github.com/go-openapi/runtime v0.19.31/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||
|
@ -27,9 +27,10 @@ type RedisConfig struct {
|
||||
}
|
||||
|
||||
type WebConfig struct {
|
||||
Listen string `yaml:"listen"`
|
||||
ListenTLS string `yaml:"listen_tls"`
|
||||
LoadLocalFiles bool `yaml:"load_local_files" env:"AUTHENTIK_WEB_LOAD_LOCAL_FILES"`
|
||||
Listen string `yaml:"listen"`
|
||||
ListenTLS string `yaml:"listen_tls"`
|
||||
LoadLocalFiles bool `yaml:"load_local_files" env:"AUTHENTIK_WEB_LOAD_LOCAL_FILES"`
|
||||
DisableEmbeddedOutpost bool `yaml:"disable_embedded_outpost" env:"AUTHENTIK_WEB__DISABLE_EMBEDDED_OUTPOST"`
|
||||
}
|
||||
|
||||
type PathsConfig struct {
|
||||
|
@ -17,4 +17,4 @@ func OutpostUserAgent() string {
|
||||
return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD())
|
||||
}
|
||||
|
||||
const VERSION = "2021.8.1-rc2"
|
||||
const VERSION = "2021.8.4"
|
||||
|
@ -152,7 +152,9 @@ func (fe *FlowExecutor) solveFlowChallenge(depth int) (bool, error) {
|
||||
responseReq := fe.api.FlowsApi.FlowsExecutorSolve(scsp.Context(), fe.flowSlug).Query(fe.Params.Encode())
|
||||
switch ch.GetComponent() {
|
||||
case string(StageIdentification):
|
||||
responseReq = responseReq.FlowChallengeResponseRequest(api.IdentificationChallengeResponseRequestAsFlowChallengeResponseRequest(api.NewIdentificationChallengeResponseRequest(fe.getAnswer(StageIdentification))))
|
||||
r := api.NewIdentificationChallengeResponseRequest(fe.getAnswer(StageIdentification))
|
||||
r.SetPassword(fe.getAnswer(StagePassword))
|
||||
responseReq = responseReq.FlowChallengeResponseRequest(api.IdentificationChallengeResponseRequestAsFlowChallengeResponseRequest(r))
|
||||
case string(StagePassword):
|
||||
responseReq = responseReq.FlowChallengeResponseRequest(api.PasswordChallengeResponseRequestAsFlowChallengeResponseRequest(api.NewPasswordChallengeResponseRequest(fe.getAnswer(StagePassword))))
|
||||
case string(StageAuthenticatorValidate):
|
||||
|
@ -23,11 +23,12 @@ type BindRequest struct {
|
||||
func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) {
|
||||
span := sentry.StartSpan(context.TODO(), "authentik.providers.ldap.bind",
|
||||
sentry.TransactionName("authentik.providers.ldap.bind"))
|
||||
rid := uuid.New().String()
|
||||
span.SetTag("request_uid", rid)
|
||||
span.SetTag("user.username", bindDN)
|
||||
defer span.Finish()
|
||||
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
rid := uuid.New().String()
|
||||
req := BindRequest{
|
||||
BindDN: bindDN,
|
||||
BindPW: bindPW,
|
||||
|
32
internal/outpost/ldap/close.go
Normal file
32
internal/outpost/ldap/close.go
Normal file
@ -0,0 +1,32 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (ls *LDAPServer) Close(boundDN string, conn net.Conn) error {
|
||||
for _, p := range ls.providers {
|
||||
p.delayDeleteUserInfo(boundDN)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) delayDeleteUserInfo(dn string) {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
quit := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
pi.boundUsersMutex.Lock()
|
||||
delete(pi.boundUsers, dn)
|
||||
pi.boundUsersMutex.Unlock()
|
||||
close(quit)
|
||||
case <-quit:
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
@ -83,7 +82,6 @@ func (pi *ProviderInstance) Bind(username string, req BindRequest) (ldap.LDAPRes
|
||||
}
|
||||
uisp.Finish()
|
||||
defer pi.boundUsersMutex.Unlock()
|
||||
pi.delayDeleteUserInfo(username)
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
@ -100,25 +98,6 @@ func (pi *ProviderInstance) SearchAccessCheck(user api.UserSelf) *string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) delayDeleteUserInfo(dn string) {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
quit := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
pi.boundUsersMutex.Lock()
|
||||
delete(pi.boundUsers, dn)
|
||||
pi.boundUsersMutex.Unlock()
|
||||
close(quit)
|
||||
case <-quit:
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (pi *ProviderInstance) TimerFlowCacheExpiry() {
|
||||
fe := outpost.NewFlowExecutor(context.Background(), pi.flowSlug, pi.s.ac.Client.GetConfig(), log.Fields{})
|
||||
fe.Params.Add("goauthentik.io/outpost/ldap", "true")
|
||||
|
@ -83,5 +83,6 @@ func NewServer(ac *ak.APIController) *LDAPServer {
|
||||
ls.defaultCert = &defaultCert
|
||||
s.BindFunc("", ls)
|
||||
s.SearchFunc("", ls)
|
||||
s.CloseFunc("", ls)
|
||||
return ls
|
||||
}
|
||||
|
@ -24,12 +24,13 @@ type SearchRequest struct {
|
||||
|
||||
func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) {
|
||||
span := sentry.StartSpan(context.TODO(), "authentik.providers.ldap.search", sentry.TransactionName("authentik.providers.ldap.search"))
|
||||
rid := uuid.New().String()
|
||||
span.SetTag("request_uid", rid)
|
||||
span.SetTag("user.username", bindDN)
|
||||
span.SetTag("ak_filter", searchReq.Filter)
|
||||
span.SetTag("ak_base_dn", searchReq.BaseDN)
|
||||
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
rid := uuid.New().String()
|
||||
req := SearchRequest{
|
||||
SearchRequest: searchReq,
|
||||
BindDN: bindDN,
|
||||
|
@ -25,6 +25,7 @@ type providerBundle struct {
|
||||
Host string
|
||||
|
||||
endSessionUrl string
|
||||
Mode *api.ProxyMode
|
||||
|
||||
cert *tls.Certificate
|
||||
|
||||
@ -38,8 +39,8 @@ func intToPointer(i int) *int {
|
||||
func (pb *providerBundle) replaceLocal(url string) string {
|
||||
if strings.HasPrefix(url, "http://localhost:8000") {
|
||||
authentikHost, c := pb.s.ak.Outpost.Config["authentik_host"]
|
||||
if !c {
|
||||
pb.log.Warning("Outpost has localhost API Connection but no authentik_host is configured.")
|
||||
if !c || authentikHost == "" {
|
||||
pb.log.Warning("Outpost has localhost/blank API Connection but no authentik_host is configured.")
|
||||
return url
|
||||
}
|
||||
f := strings.ReplaceAll(url, "http://localhost:8000", authentikHost.(string))
|
||||
@ -49,6 +50,10 @@ func (pb *providerBundle) replaceLocal(url string) string {
|
||||
}
|
||||
|
||||
func (pb *providerBundle) prepareOpts(provider api.ProxyOutpostConfig) *options.Options {
|
||||
// We need to save the mode in the bundle
|
||||
// Since for the embedded outpost we only switch for fully proxy providers
|
||||
pb.Mode = provider.Mode
|
||||
|
||||
externalHost, err := url.Parse(provider.ExternalHost)
|
||||
if err != nil {
|
||||
log.WithError(err).Warning("Failed to parse URL, skipping provider")
|
||||
|
@ -121,7 +121,7 @@ func NewOAuthProxy(opts *options.Options, provider api.ProxyOutpostConfig, c *ht
|
||||
redirectURL.Path = fmt.Sprintf("%s/callback", opts.ProxyPrefix)
|
||||
}
|
||||
|
||||
logger.Printf("proxy instance configured for Client ID: %s", opts.ClientID)
|
||||
logger.WithField("auth_url", opts.GetProvider().Data().LoginURL).WithField("client_id", opts.ClientID).Info("proxy instance configured")
|
||||
|
||||
sessionChain := buildSessionChain(opts, sessionStore)
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"goauthentik.io/api"
|
||||
"goauthentik.io/internal/utils/web"
|
||||
)
|
||||
|
||||
@ -36,10 +37,12 @@ func (ws *WebServer) configureProxy() {
|
||||
ws.m.PathPrefix("/").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
host := web.GetHost(r)
|
||||
if ws.ProxyServer != nil {
|
||||
if _, ok := ws.ProxyServer.Handlers[host]; ok {
|
||||
ws.log.WithField("host", host).Trace("routing to proxy outpost")
|
||||
ws.ProxyServer.Handler(rw, r)
|
||||
return
|
||||
if p, ok := ws.ProxyServer.Handlers[host]; ok {
|
||||
if *p.Mode == api.PROXYMODE_PROXY {
|
||||
ws.log.WithField("host", host).Trace("routing to proxy outpost")
|
||||
ws.ProxyServer.Handler(rw, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
ws.log.WithField("host", host).Trace("routing to application server")
|
||||
|
2301
schema.yml
2301
schema.yml
File diff suppressed because it is too large
Load Diff
@ -1,13 +0,0 @@
|
||||
"""Helper script to get the actual branch name, docker safe"""
|
||||
import os
|
||||
from time import time
|
||||
|
||||
env_pr_branch = "SYSTEM_PULLREQUEST_SOURCEBRANCH"
|
||||
default_branch = "BUILD_SOURCEBRANCHNAME"
|
||||
|
||||
branch_name = os.environ[default_branch]
|
||||
if env_pr_branch in os.environ:
|
||||
branch_name = os.environ[env_pr_branch].replace("/", "-")
|
||||
|
||||
print("##vso[task.setvariable variable=branchName]%s" % branch_name)
|
||||
print("##vso[task.setvariable variable=timestamp]%s" % int(time()))
|
7
scripts/ci_prepare.sh
Executable file
7
scripts/ci_prepare.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
docker-compose -f scripts/ci.docker-compose.yml up -d
|
||||
sudo apt update
|
||||
sudo apt install -y libxmlsec1-dev pkg-config
|
||||
sudo pip install -U wheel pipenv
|
||||
pipenv install --dev
|
||||
pipenv run python -m scripts.generate_ci_config
|
16
scripts/gh_do_set_branch.py
Normal file
16
scripts/gh_do_set_branch.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""Helper script to get the actual branch name, docker safe"""
|
||||
import os
|
||||
from time import time
|
||||
|
||||
env_pr_branch = "GITHUB_HEAD_REF"
|
||||
default_branch = "GITHUB_REF"
|
||||
sha = "GITHUB_SHA"
|
||||
|
||||
branch_name = os.environ[default_branch]
|
||||
if os.environ.get(env_pr_branch, "") != "":
|
||||
branch_name = os.environ[env_pr_branch]
|
||||
branch_name = branch_name.replace("refs/heads/", "").replace("/", "-")
|
||||
|
||||
print("##[set-output name=branchName]%s" % branch_name)
|
||||
print("##[set-output name=timestamp]%s" % int(time()))
|
||||
print("##[set-output name=sha]%s" % os.environ[sha])
|
@ -6,4 +6,3 @@ dist
|
||||
coverage
|
||||
# don't lint generated code
|
||||
api/
|
||||
azure-pipelines.yml
|
||||
|
@ -1,93 +0,0 @@
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- next
|
||||
- version-*
|
||||
|
||||
stages:
|
||||
- stage: lint
|
||||
jobs:
|
||||
- job: eslint
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
workingDir: 'web/'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: make gen-web
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'custom'
|
||||
workingDir: 'web/'
|
||||
customCommand: 'run lint'
|
||||
- job: prettier
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
workingDir: 'web/'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: make gen-web
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'custom'
|
||||
workingDir: 'web/'
|
||||
customCommand: 'run prettier-check'
|
||||
- job: lit_analyse
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
workingDir: 'web/'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: make gen-web
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'custom'
|
||||
workingDir: 'web/'
|
||||
customCommand: 'run lit-analyse'
|
||||
- stage: build_local
|
||||
jobs:
|
||||
- job: build
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'install'
|
||||
workingDir: 'web/'
|
||||
- task: CmdLine@2
|
||||
inputs:
|
||||
script: make gen-web
|
||||
- task: Npm@1
|
||||
inputs:
|
||||
command: 'custom'
|
||||
workingDir: 'web/'
|
||||
customCommand: 'run build'
|
334
web/package-lock.json
generated
334
web/package-lock.json
generated
@ -15,23 +15,23 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"@goauthentik/api": "^2021.8.1-rc1-1629828588",
|
||||
"@goauthentik/api": "^2021.8.3-1630597235",
|
||||
"@lingui/cli": "^3.10.2",
|
||||
"@lingui/core": "^3.10.4",
|
||||
"@lingui/macro": "^3.10.2",
|
||||
"@patternfly/patternfly": "^4.125.3",
|
||||
"@patternfly/patternfly": "^4.132.2",
|
||||
"@polymer/iron-form": "^3.0.1",
|
||||
"@polymer/paper-input": "^3.2.1",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-replace": "^3.0.0",
|
||||
"@rollup/plugin-typescript": "^8.2.5",
|
||||
"@sentry/browser": "^6.11.0",
|
||||
"@sentry/tracing": "^6.11.0",
|
||||
"@sentry/browser": "^6.12.0",
|
||||
"@sentry/tracing": "^6.12.0",
|
||||
"@types/chart.js": "^2.9.34",
|
||||
"@types/codemirror": "5.60.2",
|
||||
"@types/grecaptcha": "^3.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.3",
|
||||
"@typescript-eslint/parser": "^4.29.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.30.0",
|
||||
"@typescript-eslint/parser": "^4.30.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.6.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"base64-js": "^1.5.1",
|
||||
@ -59,7 +59,7 @@
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.3.5",
|
||||
"typescript": "^4.4.2",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
@ -1689,9 +1689,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@goauthentik/api": {
|
||||
"version": "2021.8.1-rc1-1629828588",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2021.8.1-rc1-1629828588.tgz",
|
||||
"integrity": "sha512-MI/ZlW0fp/7JGFvPrxANBIErGsxkcQ9tWZ86LkFbn+qfob6KrD0tdYlNxab7EVoovLUZbdOGgvfCR+YO4XFBwg=="
|
||||
"version": "2021.8.3-1630597235",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2021.8.3-1630597235.tgz",
|
||||
"integrity": "sha512-W/AWgWE8WS8pWYPqy9JuzbzdYcTJ7aCjzgcLbOmD4roYTp1vP1znSZKx0zg9ZH7EBskFfDqm2eAueF1ktPC09g=="
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.5.0",
|
||||
@ -2071,9 +2071,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@patternfly/patternfly": {
|
||||
"version": "4.125.3",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.125.3.tgz",
|
||||
"integrity": "sha512-B0L3TFdFYsioV1loCsd3s3Y6eNV/9YjHQIlFnxF1KRgj+eVq0idKi1Mnq28eycKQgFi6ld3tEveMSxBsaw3R9A=="
|
||||
"version": "4.132.2",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.132.2.tgz",
|
||||
"integrity": "sha512-66qBgIpwPPeTUMTUUO6Z73XApvNXxn3uFaXMeVa09viYGDKzEX3L1FIfc4VzVk2okhk/9KJIYYgxofeuGi5v6A=="
|
||||
},
|
||||
"node_modules/@polymer/font-roboto": {
|
||||
"version": "3.0.2",
|
||||
@ -2276,13 +2276,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.11.0.tgz",
|
||||
"integrity": "sha512-Qr2QRA0t5/S9QQqxzYKvM9W8prvmiWuldfwRX4hubovXzcXLgUi4WK0/H612wSbYZ4dNAEcQbtlxFWJNN4wxdg==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.12.0.tgz",
|
||||
"integrity": "sha512-wsJi1NLOmfwtPNYxEC50dpDcVY7sdYckzwfqz1/zHrede1mtxpqSw+7iP4bHADOJXuF+ObYYTHND0v38GSXznQ==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/core": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2295,14 +2295,14 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.11.0.tgz",
|
||||
"integrity": "sha512-09TB+f3pqEq8LFahFWHO6I/4DxHo+NcS52OkbWMDqEi6oNZRD7PhPn3i14LfjsYVv3u3AESU8oxSEGbFrr2UjQ==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.12.0.tgz",
|
||||
"integrity": "sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.11.0",
|
||||
"@sentry/minimal": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/hub": "6.12.0",
|
||||
"@sentry/minimal": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2315,12 +2315,12 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/hub": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.11.0.tgz",
|
||||
"integrity": "sha512-pT9hf+ZJfVFpoZopoC+yJmFNclr4NPqPcl2cgguqCHb69DklD1NxgBNWK8D6X05qjnNFDF991U6t1mxP9HrGuw==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.12.0.tgz",
|
||||
"integrity": "sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2333,12 +2333,12 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/minimal": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.11.0.tgz",
|
||||
"integrity": "sha512-XkZ7qrdlGp4IM/gjGxf1Q575yIbl5RvPbg+WFeekpo16Ufvzx37Mr8c2xsZaWosISVyE6eyFpooORjUlzy8EDw==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.12.0.tgz",
|
||||
"integrity": "sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/hub": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2351,14 +2351,14 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/tracing": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.11.0.tgz",
|
||||
"integrity": "sha512-9VA1/SY++WeoMQI4K6n/sYgIdRtCu9NLWqmGqu/5kbOtESYFgAt1DqSyqGCr00ZjQiC2s7tkDkTNZb38K6KytQ==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.12.0.tgz",
|
||||
"integrity": "sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "6.11.0",
|
||||
"@sentry/minimal": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/hub": "6.12.0",
|
||||
"@sentry/minimal": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2371,19 +2371,19 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.11.0.tgz",
|
||||
"integrity": "sha512-gm5H9eZhL6bsIy/h3T+/Fzzz2vINhHhqd92CjHle3w7uXdTdFV98i2pDpErBGNTSNzbntqOMifYEB5ENtZAvcg==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.12.0.tgz",
|
||||
"integrity": "sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.11.0.tgz",
|
||||
"integrity": "sha512-IOvyFHcnbRQxa++jO+ZUzRvFHEJ1cZjrBIQaNVc0IYF0twUOB5PTP6joTcix38ldaLeapaPZ9LGfudbvYvxkdg==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.12.0.tgz",
|
||||
"integrity": "sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2557,12 +2557,12 @@
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz",
|
||||
"integrity": "sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.30.0.tgz",
|
||||
"integrity": "sha512-NgAnqk55RQ/SD+tZFD9aPwNSeHmDHHe5rtUyhIq0ZeCWZEvo4DK9rYz7v9HDuQZFvn320Ot+AikaCKMFKLlD0g==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/experimental-utils": "4.29.3",
|
||||
"@typescript-eslint/scope-manager": "4.29.3",
|
||||
"@typescript-eslint/experimental-utils": "4.30.0",
|
||||
"@typescript-eslint/scope-manager": "4.30.0",
|
||||
"debug": "^4.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"regexpp": "^3.1.0",
|
||||
@ -2601,14 +2601,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/experimental-utils": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz",
|
||||
"integrity": "sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz",
|
||||
"integrity": "sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"@typescript-eslint/scope-manager": "4.29.3",
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/typescript-estree": "4.29.3",
|
||||
"@typescript-eslint/scope-manager": "4.30.0",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/typescript-estree": "4.30.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
@ -2624,13 +2624,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.3.tgz",
|
||||
"integrity": "sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.30.0.tgz",
|
||||
"integrity": "sha512-HJ0XuluSZSxeboLU7Q2VQ6eLlCwXPBOGnA7CqgBnz2Db3JRQYyBDJgQnop6TZ+rsbSx5gEdWhw4rE4mDa1FnZg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "4.29.3",
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/typescript-estree": "4.29.3",
|
||||
"@typescript-eslint/scope-manager": "4.30.0",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/typescript-estree": "4.30.0",
|
||||
"debug": "^4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -2650,12 +2650,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz",
|
||||
"integrity": "sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.30.0.tgz",
|
||||
"integrity": "sha512-VJ/jAXovxNh7rIXCQbYhkyV2Y3Ac/0cVHP/FruTJSAUUm4Oacmn/nkN5zfWmWFEanN4ggP0vJSHOeajtHq3f8A==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/visitor-keys": "4.29.3"
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/visitor-keys": "4.30.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||
@ -2666,9 +2666,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.3.tgz",
|
||||
"integrity": "sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.30.0.tgz",
|
||||
"integrity": "sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw==",
|
||||
"engines": {
|
||||
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
|
||||
},
|
||||
@ -2678,12 +2678,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz",
|
||||
"integrity": "sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz",
|
||||
"integrity": "sha512-6WN7UFYvykr/U0Qgy4kz48iGPWILvYL34xXJxvDQeiRE018B7POspNRVtAZscWntEPZpFCx4hcz/XBT+erenfg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/visitor-keys": "4.29.3",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/visitor-keys": "4.30.0",
|
||||
"debug": "^4.3.1",
|
||||
"globby": "^11.0.3",
|
||||
"is-glob": "^4.0.1",
|
||||
@ -2718,11 +2718,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz",
|
||||
"integrity": "sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz",
|
||||
"integrity": "sha512-pNaaxDt/Ol/+JZwzP7MqWc8PJQTUhZwoee/PVlQ+iYoYhagccvoHnC9e4l+C/krQYYkENxznhVSDwClIbZVxRw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -8021,9 +8021,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
|
||||
"integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@ -9566,9 +9566,9 @@
|
||||
"integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg=="
|
||||
},
|
||||
"@goauthentik/api": {
|
||||
"version": "2021.8.1-rc1-1629828588",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2021.8.1-rc1-1629828588.tgz",
|
||||
"integrity": "sha512-MI/ZlW0fp/7JGFvPrxANBIErGsxkcQ9tWZ86LkFbn+qfob6KrD0tdYlNxab7EVoovLUZbdOGgvfCR+YO4XFBwg=="
|
||||
"version": "2021.8.3-1630597235",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2021.8.3-1630597235.tgz",
|
||||
"integrity": "sha512-W/AWgWE8WS8pWYPqy9JuzbzdYcTJ7aCjzgcLbOmD4roYTp1vP1znSZKx0zg9ZH7EBskFfDqm2eAueF1ktPC09g=="
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.5.0",
|
||||
@ -9847,9 +9847,9 @@
|
||||
}
|
||||
},
|
||||
"@patternfly/patternfly": {
|
||||
"version": "4.125.3",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.125.3.tgz",
|
||||
"integrity": "sha512-B0L3TFdFYsioV1loCsd3s3Y6eNV/9YjHQIlFnxF1KRgj+eVq0idKi1Mnq28eycKQgFi6ld3tEveMSxBsaw3R9A=="
|
||||
"version": "4.132.2",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.132.2.tgz",
|
||||
"integrity": "sha512-66qBgIpwPPeTUMTUUO6Z73XApvNXxn3uFaXMeVa09viYGDKzEX3L1FIfc4VzVk2okhk/9KJIYYgxofeuGi5v6A=="
|
||||
},
|
||||
"@polymer/font-roboto": {
|
||||
"version": "3.0.2",
|
||||
@ -10022,13 +10022,13 @@
|
||||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.11.0.tgz",
|
||||
"integrity": "sha512-Qr2QRA0t5/S9QQqxzYKvM9W8prvmiWuldfwRX4hubovXzcXLgUi4WK0/H612wSbYZ4dNAEcQbtlxFWJNN4wxdg==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.12.0.tgz",
|
||||
"integrity": "sha512-wsJi1NLOmfwtPNYxEC50dpDcVY7sdYckzwfqz1/zHrede1mtxpqSw+7iP4bHADOJXuF+ObYYTHND0v38GSXznQ==",
|
||||
"requires": {
|
||||
"@sentry/core": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/core": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10040,14 +10040,14 @@
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.11.0.tgz",
|
||||
"integrity": "sha512-09TB+f3pqEq8LFahFWHO6I/4DxHo+NcS52OkbWMDqEi6oNZRD7PhPn3i14LfjsYVv3u3AESU8oxSEGbFrr2UjQ==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.12.0.tgz",
|
||||
"integrity": "sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.11.0",
|
||||
"@sentry/minimal": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/hub": "6.12.0",
|
||||
"@sentry/minimal": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10059,12 +10059,12 @@
|
||||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.11.0.tgz",
|
||||
"integrity": "sha512-pT9hf+ZJfVFpoZopoC+yJmFNclr4NPqPcl2cgguqCHb69DklD1NxgBNWK8D6X05qjnNFDF991U6t1mxP9HrGuw==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.12.0.tgz",
|
||||
"integrity": "sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10076,12 +10076,12 @@
|
||||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.11.0.tgz",
|
||||
"integrity": "sha512-XkZ7qrdlGp4IM/gjGxf1Q575yIbl5RvPbg+WFeekpo16Ufvzx37Mr8c2xsZaWosISVyE6eyFpooORjUlzy8EDw==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.12.0.tgz",
|
||||
"integrity": "sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/hub": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10093,14 +10093,14 @@
|
||||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.11.0.tgz",
|
||||
"integrity": "sha512-9VA1/SY++WeoMQI4K6n/sYgIdRtCu9NLWqmGqu/5kbOtESYFgAt1DqSyqGCr00ZjQiC2s7tkDkTNZb38K6KytQ==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.12.0.tgz",
|
||||
"integrity": "sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==",
|
||||
"requires": {
|
||||
"@sentry/hub": "6.11.0",
|
||||
"@sentry/minimal": "6.11.0",
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/utils": "6.11.0",
|
||||
"@sentry/hub": "6.12.0",
|
||||
"@sentry/minimal": "6.12.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"@sentry/utils": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10112,16 +10112,16 @@
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.11.0.tgz",
|
||||
"integrity": "sha512-gm5H9eZhL6bsIy/h3T+/Fzzz2vINhHhqd92CjHle3w7uXdTdFV98i2pDpErBGNTSNzbntqOMifYEB5ENtZAvcg=="
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.12.0.tgz",
|
||||
"integrity": "sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.11.0.tgz",
|
||||
"integrity": "sha512-IOvyFHcnbRQxa++jO+ZUzRvFHEJ1cZjrBIQaNVc0IYF0twUOB5PTP6joTcix38ldaLeapaPZ9LGfudbvYvxkdg==",
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.12.0.tgz",
|
||||
"integrity": "sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==",
|
||||
"requires": {
|
||||
"@sentry/types": "6.11.0",
|
||||
"@sentry/types": "6.12.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10292,12 +10292,12 @@
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz",
|
||||
"integrity": "sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.30.0.tgz",
|
||||
"integrity": "sha512-NgAnqk55RQ/SD+tZFD9aPwNSeHmDHHe5rtUyhIq0ZeCWZEvo4DK9rYz7v9HDuQZFvn320Ot+AikaCKMFKLlD0g==",
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "4.29.3",
|
||||
"@typescript-eslint/scope-manager": "4.29.3",
|
||||
"@typescript-eslint/experimental-utils": "4.30.0",
|
||||
"@typescript-eslint/scope-manager": "4.30.0",
|
||||
"debug": "^4.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"regexpp": "^3.1.0",
|
||||
@ -10316,50 +10316,50 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz",
|
||||
"integrity": "sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz",
|
||||
"integrity": "sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.7",
|
||||
"@typescript-eslint/scope-manager": "4.29.3",
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/typescript-estree": "4.29.3",
|
||||
"@typescript-eslint/scope-manager": "4.30.0",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/typescript-estree": "4.30.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.3.tgz",
|
||||
"integrity": "sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.30.0.tgz",
|
||||
"integrity": "sha512-HJ0XuluSZSxeboLU7Q2VQ6eLlCwXPBOGnA7CqgBnz2Db3JRQYyBDJgQnop6TZ+rsbSx5gEdWhw4rE4mDa1FnZg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "4.29.3",
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/typescript-estree": "4.29.3",
|
||||
"@typescript-eslint/scope-manager": "4.30.0",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/typescript-estree": "4.30.0",
|
||||
"debug": "^4.3.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz",
|
||||
"integrity": "sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.30.0.tgz",
|
||||
"integrity": "sha512-VJ/jAXovxNh7rIXCQbYhkyV2Y3Ac/0cVHP/FruTJSAUUm4Oacmn/nkN5zfWmWFEanN4ggP0vJSHOeajtHq3f8A==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/visitor-keys": "4.29.3"
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/visitor-keys": "4.30.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.3.tgz",
|
||||
"integrity": "sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg=="
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.30.0.tgz",
|
||||
"integrity": "sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw=="
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz",
|
||||
"integrity": "sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz",
|
||||
"integrity": "sha512-6WN7UFYvykr/U0Qgy4kz48iGPWILvYL34xXJxvDQeiRE018B7POspNRVtAZscWntEPZpFCx4hcz/XBT+erenfg==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/visitor-keys": "4.29.3",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"@typescript-eslint/visitor-keys": "4.30.0",
|
||||
"debug": "^4.3.1",
|
||||
"globby": "^11.0.3",
|
||||
"is-glob": "^4.0.1",
|
||||
@ -10378,11 +10378,11 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "4.29.3",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz",
|
||||
"integrity": "sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA==",
|
||||
"version": "4.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz",
|
||||
"integrity": "sha512-pNaaxDt/Ol/+JZwzP7MqWc8PJQTUhZwoee/PVlQ+iYoYhagccvoHnC9e4l+C/krQYYkENxznhVSDwClIbZVxRw==",
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "4.29.3",
|
||||
"@typescript-eslint/types": "4.30.0",
|
||||
"eslint-visitor-keys": "^2.0.0"
|
||||
}
|
||||
},
|
||||
@ -14339,9 +14339,9 @@
|
||||
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA=="
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
|
||||
"integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ=="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.14.1",
|
||||
|
@ -46,23 +46,23 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"@goauthentik/api": "^2021.8.1-rc1-1629828588",
|
||||
"@goauthentik/api": "^2021.8.3-1630597235",
|
||||
"@lingui/cli": "^3.10.2",
|
||||
"@lingui/core": "^3.10.4",
|
||||
"@lingui/macro": "^3.10.2",
|
||||
"@patternfly/patternfly": "^4.125.3",
|
||||
"@patternfly/patternfly": "^4.132.2",
|
||||
"@polymer/iron-form": "^3.0.1",
|
||||
"@polymer/paper-input": "^3.2.1",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-replace": "^3.0.0",
|
||||
"@rollup/plugin-typescript": "^8.2.5",
|
||||
"@sentry/browser": "^6.11.0",
|
||||
"@sentry/tracing": "^6.11.0",
|
||||
"@sentry/browser": "^6.12.0",
|
||||
"@sentry/tracing": "^6.12.0",
|
||||
"@types/chart.js": "^2.9.34",
|
||||
"@types/codemirror": "5.60.2",
|
||||
"@types/grecaptcha": "^3.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.3",
|
||||
"@typescript-eslint/parser": "^4.29.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.30.0",
|
||||
"@typescript-eslint/parser": "^4.30.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.6.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"base64-js": "^1.5.1",
|
||||
@ -90,7 +90,7 @@
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"ts-lit-plugin": "^1.2.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.3.5",
|
||||
"typescript": "^4.4.2",
|
||||
"webcomponent-qr-code": "^1.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { Config, Configuration, CoreApi, CurrentTenant, Middleware, ResponseCont
|
||||
import { getCookie } from "../utils";
|
||||
import { APIMiddleware } from "../elements/notifications/APIDrawer";
|
||||
import { MessageMiddleware } from "../elements/messages/Middleware";
|
||||
import { VERSION } from "../constants";
|
||||
|
||||
export class LoggingMiddleware implements Middleware {
|
||||
|
||||
@ -49,7 +50,7 @@ export function tenant(): Promise<CurrentTenant> {
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG = new Configuration({
|
||||
basePath: "",
|
||||
basePath: "/api/v3",
|
||||
headers: {
|
||||
"X-CSRFToken": getCookie("authentik_csrf"),
|
||||
},
|
||||
@ -59,3 +60,5 @@ export const DEFAULT_CONFIG = new Configuration({
|
||||
new LoggingMiddleware(),
|
||||
],
|
||||
});
|
||||
|
||||
console.debug(`authentik(early): version ${VERSION}`);
|
||||
|
@ -15,7 +15,7 @@ export function configureSentry(canDoPpi: boolean = false): Promise<Config> {
|
||||
Sentry.init({
|
||||
dsn: "https://a579bb09306d4f8b8d8847c052d3a1d3@sentry.beryju.org/8",
|
||||
release: `authentik@${VERSION}`,
|
||||
tunnel: "/api/v2beta/sentry/",
|
||||
tunnel: "/api/v3/sentry/",
|
||||
integrations: [
|
||||
new Integrations.BrowserTracing({
|
||||
tracingOrigins: [window.location.host, "localhost"],
|
||||
|
@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
|
||||
export const ERROR_CLASS = "pf-m-danger";
|
||||
export const PROGRESS_CLASS = "pf-m-in-progress";
|
||||
export const CURRENT_CLASS = "pf-m-current";
|
||||
export const VERSION = "2021.8.1-rc2";
|
||||
export const VERSION = "2021.8.4";
|
||||
export const PAGE_SIZE = 20;
|
||||
export const TITLE_DEFAULT = "authentik";
|
||||
export const ROUTE_SEPARATOR = ";";
|
||||
|
@ -136,6 +136,11 @@ export class Form<T> extends LitElement {
|
||||
json[element.name] = values;
|
||||
} else if (element.tagName.toLowerCase() === "input" && element.type === "date") {
|
||||
json[element.name] = element.valueAsDate;
|
||||
} else if (
|
||||
element.tagName.toLowerCase() === "input" &&
|
||||
element.type === "datetime-local"
|
||||
) {
|
||||
json[element.name] = new Date(element.valueAsNumber);
|
||||
} else if (element.tagName.toLowerCase() === "input" && element.type === "checkbox") {
|
||||
json[element.name] = element.checked;
|
||||
} else {
|
||||
@ -219,9 +224,15 @@ export class Form<T> extends LitElement {
|
||||
throw ex;
|
||||
})
|
||||
.catch((ex: Error) => {
|
||||
let msg = ex.toString();
|
||||
// Only change the message when we have `detail`.
|
||||
// Everything else is handled in the form.
|
||||
if (ex instanceof APIError && "detail" in ex.response) {
|
||||
msg = ex.response.detail;
|
||||
}
|
||||
// error is local or not from rest_framework
|
||||
showMessage({
|
||||
message: ex.toString(),
|
||||
message: msg,
|
||||
level: MessageLevel.error,
|
||||
});
|
||||
// rethrow the error so the form doesn't close
|
||||
|
@ -55,8 +55,34 @@ import { WebsocketClient } from "../common/ws";
|
||||
export class FlowExecutor extends LitElement implements StageHost {
|
||||
flowSlug: string;
|
||||
|
||||
private _challenge?: ChallengeTypes;
|
||||
|
||||
@property({ attribute: false })
|
||||
challenge?: ChallengeTypes;
|
||||
set challenge(value: ChallengeTypes | undefined) {
|
||||
this._challenge = value;
|
||||
// Assign the location as soon as we get the challenge and *not* in the render function
|
||||
// as the render function might be called multiple times, which will navigate multiple
|
||||
// times and can invalidate oauth codes
|
||||
if (value?.type === ChallengeChoices.Redirect) {
|
||||
console.debug(
|
||||
"authentik/flows: redirecting to url from server",
|
||||
(value as RedirectChallenge).to,
|
||||
);
|
||||
window.location.assign((value as RedirectChallenge).to);
|
||||
}
|
||||
tenant().then((tenant) => {
|
||||
if (value?.flowInfo?.title) {
|
||||
document.title = `${value.flowInfo?.title} - ${tenant.brandingTitle}`;
|
||||
} else {
|
||||
document.title = tenant.brandingTitle || TITLE_DEFAULT;
|
||||
}
|
||||
});
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
get challenge(): ChallengeTypes | undefined {
|
||||
return this._challenge;
|
||||
}
|
||||
|
||||
@property({ type: Boolean })
|
||||
loading = false;
|
||||
@ -95,16 +121,6 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||
});
|
||||
}
|
||||
|
||||
private postUpdate(): void {
|
||||
tenant().then((tenant) => {
|
||||
if (this.challenge?.flowInfo?.title) {
|
||||
document.title = `${this.challenge.flowInfo?.title} - ${tenant.brandingTitle}`;
|
||||
} else {
|
||||
document.title = tenant.brandingTitle || TITLE_DEFAULT;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
submit(payload?: FlowChallengeResponseRequest): Promise<void> {
|
||||
if (!payload) return Promise.reject();
|
||||
if (!this.challenge) return Promise.reject();
|
||||
@ -119,7 +135,6 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||
})
|
||||
.then((data) => {
|
||||
this.challenge = data;
|
||||
this.postUpdate();
|
||||
})
|
||||
.catch((e: Error | Response) => {
|
||||
this.errorMessage(e);
|
||||
@ -144,7 +159,6 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||
if (this.challenge?.flowInfo?.background) {
|
||||
this.setBackground(this.challenge.flowInfo.background);
|
||||
}
|
||||
this.postUpdate();
|
||||
})
|
||||
.catch((e: Error | Response) => {
|
||||
// Catch JSON or Update errors
|
||||
@ -189,11 +203,6 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||
}
|
||||
switch (this.challenge.type) {
|
||||
case ChallengeChoices.Redirect:
|
||||
console.debug(
|
||||
"authentik/flows: redirecting to url from server",
|
||||
(this.challenge as RedirectChallenge).to,
|
||||
);
|
||||
window.location.assign((this.challenge as RedirectChallenge).to);
|
||||
return html`<ak-empty-state ?loading=${true} header=${t`Loading`}>
|
||||
</ak-empty-state>`;
|
||||
case ChallengeChoices.Shell:
|
||||
|
@ -180,7 +180,7 @@ export class AuthenticatorValidateStage
|
||||
${this.selectedDeviceChallenge
|
||||
? ""
|
||||
: html`<p class="pf-c-login__main-header-desc">
|
||||
${t`Select an identification method.`}
|
||||
${t`Select an authentication method.`}
|
||||
</p>`}
|
||||
</header>
|
||||
${this.selectedDeviceChallenge
|
||||
|
@ -64,13 +64,6 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||
placeholder="${prompt.placeholder}"
|
||||
class="pf-c-form-control"
|
||||
?required=${prompt.required}>`;
|
||||
case "checkbox":
|
||||
return `<input
|
||||
type="checkbox"
|
||||
name="${prompt.fieldKey}"
|
||||
placeholder="${prompt.placeholder}"
|
||||
class="pf-c-form-control"
|
||||
?required=${prompt.required}>`;
|
||||
case "date":
|
||||
return `<input
|
||||
type="date"
|
||||
@ -115,6 +108,22 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||
}}
|
||||
>
|
||||
${this.challenge.fields.map((prompt) => {
|
||||
// Checkbox is rendered differently
|
||||
if (prompt.type === "checkbox") {
|
||||
return html`<div class="pf-c-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="pf-c-check__input"
|
||||
name="${prompt.fieldKey}"
|
||||
?checked=${prompt.placeholder !== ""}
|
||||
?required=${prompt.required}
|
||||
/>
|
||||
<label class="pf-c-check__label">${prompt.label}</label>
|
||||
${prompt.required
|
||||
? html`<p class="pf-c-form__helper-text">${t`Required.`}</p>`
|
||||
: html``}
|
||||
</div>`;
|
||||
}
|
||||
// Special types that aren't rendered in a wrapper
|
||||
if (
|
||||
prompt.type === "static" ||
|
||||
|
@ -275,7 +275,7 @@ export class AdminInterface extends LitElement {
|
||||
<span slot="label">${t`Certificates`}</span>
|
||||
</ak-sidebar-item>
|
||||
<ak-sidebar-item path="/core/tokens">
|
||||
<span slot="label">${t`Tokens`}</span>
|
||||
<span slot="label">${t`Tokens & App passwords`}</span>
|
||||
</ak-sidebar-item>
|
||||
</ak-sidebar-item>
|
||||
`;
|
||||
|
@ -75,6 +75,10 @@ msgstr "API Hostname"
|
||||
msgid "API Requests"
|
||||
msgstr "API Requests"
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
msgid "API Token (can be used to access the API programmatically)"
|
||||
msgstr "API Token (can be used to access the API programmatically)"
|
||||
|
||||
#: src/elements/messages/Middleware.ts
|
||||
msgid "API request failed"
|
||||
msgstr "API request failed"
|
||||
@ -239,6 +243,10 @@ msgstr "App"
|
||||
msgid "App password"
|
||||
msgstr "App password"
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
msgid "App password (can be used to login using a flow executor)"
|
||||
msgstr "App password (can be used to login using a flow executor)"
|
||||
|
||||
#: src/elements/user/UserConsentList.ts
|
||||
#: src/pages/admin-overview/TopApplicationsTable.ts
|
||||
#: src/pages/providers/ProviderListPage.ts
|
||||
@ -898,7 +906,6 @@ msgstr "Cookie domain"
|
||||
msgid "Copy"
|
||||
msgstr "Copy"
|
||||
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
msgid "Copy Key"
|
||||
msgstr "Copy Key"
|
||||
@ -954,6 +961,8 @@ msgstr "Copy recovery link"
|
||||
#: src/pages/stages/prompt/PromptStageForm.ts
|
||||
#: src/pages/tenants/TenantListPage.ts
|
||||
#: src/pages/tenants/TenantListPage.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
#: src/pages/users/UserListPage.ts
|
||||
@ -1038,6 +1047,7 @@ msgstr "Create Stage binding"
|
||||
msgid "Create Tenant"
|
||||
msgstr "Create Tenant"
|
||||
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
msgid "Create Token"
|
||||
@ -1221,6 +1231,7 @@ msgstr "Deny the user access"
|
||||
#: src/pages/applications/ApplicationForm.ts
|
||||
#: src/pages/property-mappings/PropertyMappingScopeForm.ts
|
||||
#: src/pages/system-tasks/SystemTaskListPage.ts
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenForm.ts
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
@ -1581,6 +1592,10 @@ msgstr "Execution logging"
|
||||
msgid "Expires"
|
||||
msgstr "Expires"
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
msgid "Expires on"
|
||||
msgstr "Expires on"
|
||||
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
msgid "Expires?"
|
||||
msgstr "Expires?"
|
||||
@ -1590,6 +1605,10 @@ msgstr "Expires?"
|
||||
msgid "Expiring"
|
||||
msgstr "Expiring"
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
msgid "Expiring?"
|
||||
msgstr "Expiring?"
|
||||
|
||||
#: src/pages/crypto/CertificateKeyPairListPage.ts
|
||||
#: src/pages/stages/invitation/InvitationListPage.ts
|
||||
msgid "Expiry"
|
||||
@ -1983,6 +2002,7 @@ msgstr "Icon shown in the browser tab."
|
||||
|
||||
#: src/pages/flows/FlowListPage.ts
|
||||
#: src/pages/system-tasks/SystemTaskListPage.ts
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenForm.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
@ -2018,6 +2038,10 @@ msgstr "If set, users are able to unenroll themselves using this flow. If no flo
|
||||
msgid "If this flag is set, this Stage will jump to the next Stage when no Invitation is given. By default this Stage will cancel the Flow when no invitation is given."
|
||||
msgstr "If this flag is set, this Stage will jump to the next Stage when no Invitation is given. By default this Stage will cancel the Flow when no invitation is given."
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
msgid "If this is selected, the token will expire. Upon expiration, the token will be rotated."
|
||||
msgstr "If this is selected, the token will expire. Upon expiration, the token will be rotated."
|
||||
|
||||
#: src/pages/outposts/OutpostDeploymentModal.ts
|
||||
msgid "If your authentik Instance is using a self-signed certificate, set this value."
|
||||
msgstr "If your authentik Instance is using a self-signed certificate, set this value."
|
||||
@ -2076,6 +2100,7 @@ msgstr "Integration key"
|
||||
msgid "Integrations"
|
||||
msgstr "Integrations"
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
msgid "Intent"
|
||||
@ -2331,6 +2356,7 @@ msgstr "Loading"
|
||||
#: src/pages/tenants/TenantForm.ts
|
||||
#: src/pages/tenants/TenantForm.ts
|
||||
#: src/pages/tenants/TenantForm.ts
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/users/UserForm.ts
|
||||
#: src/pages/users/UserResetEmailForm.ts
|
||||
msgid "Loading..."
|
||||
@ -3344,6 +3370,10 @@ msgstr "Request token URL"
|
||||
msgid "Required"
|
||||
msgstr "Required"
|
||||
|
||||
#: src/flows/stages/prompt/PromptStage.ts
|
||||
msgid "Required."
|
||||
msgstr "Required."
|
||||
|
||||
#: src/pages/user-settings/UserSelfForm.ts
|
||||
#: src/pages/users/ServiceAccountForm.ts
|
||||
#: src/pages/users/UserForm.ts
|
||||
@ -3498,13 +3528,17 @@ msgstr "Select a provider that this application should use. Alternatively, creat
|
||||
msgid "Select all rows"
|
||||
msgstr "Select all rows"
|
||||
|
||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||
msgid "Select an authentication method."
|
||||
msgstr "Select an authentication method."
|
||||
|
||||
#: src/pages/stages/invitation/InvitationListLink.ts
|
||||
msgid "Select an enrollment flow"
|
||||
msgstr "Select an enrollment flow"
|
||||
|
||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||
msgid "Select an identification method."
|
||||
msgstr "Select an identification method."
|
||||
#:
|
||||
#~ msgid "Select an identification method."
|
||||
#~ msgstr "Select an identification method."
|
||||
|
||||
#: src/pages/users/GroupSelectModal.ts
|
||||
msgid "Select groups to add user to"
|
||||
@ -3731,9 +3765,13 @@ msgstr "Source(s)"
|
||||
msgid "Sources"
|
||||
msgstr "Sources"
|
||||
|
||||
#:
|
||||
#~ msgid "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
#~ msgstr "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
|
||||
#: src/pages/sources/SourcesListPage.ts
|
||||
msgid "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
msgstr "Sources of identities, which can either be synced into authentik's database, like LDAP, or can be used by users to authenticate and enroll themselves, like OAuth and social logins"
|
||||
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||
msgstr "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||
|
||||
#: src/pages/flows/BoundStagesList.ts
|
||||
#: src/pages/flows/StageBindingForm.ts
|
||||
@ -3982,6 +4020,7 @@ msgstr "Successfully created stage."
|
||||
msgid "Successfully created tenant."
|
||||
msgstr "Successfully created tenant."
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenForm.ts
|
||||
msgid "Successfully created token."
|
||||
msgstr "Successfully created token."
|
||||
@ -4137,6 +4176,7 @@ msgstr "Successfully updated stage."
|
||||
msgid "Successfully updated tenant."
|
||||
msgstr "Successfully updated tenant."
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenForm.ts
|
||||
msgid "Successfully updated token."
|
||||
msgstr "Successfully updated token."
|
||||
@ -4431,11 +4471,14 @@ msgid "Token(s)"
|
||||
msgstr "Token(s)"
|
||||
|
||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||
#: src/interfaces/AdminInterface.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
msgid "Tokens"
|
||||
msgstr "Tokens"
|
||||
|
||||
#: src/interfaces/AdminInterface.ts
|
||||
msgid "Tokens & App passwords"
|
||||
msgstr "Tokens & App passwords"
|
||||
|
||||
#: src/pages/user-settings/UserSettingsPage.ts
|
||||
msgid "Tokens and App passwords"
|
||||
msgstr "Tokens and App passwords"
|
||||
@ -4545,6 +4588,10 @@ msgstr "Unhealthy"
|
||||
msgid "Unhealthy outposts"
|
||||
msgstr "Unhealthy outposts"
|
||||
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
msgid "Unique identifier the token is referenced by."
|
||||
msgstr "Unique identifier the token is referenced by."
|
||||
|
||||
#: src/pages/system-tasks/SystemTaskListPage.ts
|
||||
msgid "Unknown"
|
||||
msgstr "Unknown"
|
||||
@ -4591,6 +4638,7 @@ msgstr "Up-to-date!"
|
||||
#: src/pages/stages/StageListPage.ts
|
||||
#: src/pages/stages/prompt/PromptListPage.ts
|
||||
#: src/pages/tenants/TenantListPage.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/UserSelfForm.ts
|
||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts
|
||||
#: src/pages/user-settings/settings/UserSettingsAuthenticatorWebAuthn.ts
|
||||
@ -4680,6 +4728,7 @@ msgstr "Update Stage binding"
|
||||
msgid "Update Tenant"
|
||||
msgstr "Update Tenant"
|
||||
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
msgid "Update Token"
|
||||
msgstr "Update Token"
|
||||
@ -4769,6 +4818,7 @@ msgstr "Use this tenant for each domain that doesn't have a dedicated tenant."
|
||||
#: src/pages/policies/PolicyBindingForm.ts
|
||||
#: src/pages/policies/PolicyTestForm.ts
|
||||
#: src/pages/property-mappings/PropertyMappingTestForm.ts
|
||||
#: src/pages/tokens/TokenForm.ts
|
||||
#: src/pages/tokens/TokenListPage.ts
|
||||
#: src/pages/user-settings/tokens/UserTokenList.ts
|
||||
#: src/pages/users/UserListPage.ts
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user