Compare commits
71 Commits
version/20
...
outposts/f
Author | SHA1 | Date | |
---|---|---|---|
4e9a466d64 | |||
9bd8cfbac0 | |||
e18c2fe084 | |||
205f11532f | |||
bc6d66cd88 | |||
609e9a00b4 | |||
d5708d22e0 | |||
71ac1282f9 | |||
cf9d8f64a2 | |||
1cda01511b | |||
13591fc72c | |||
b604ff5114 | |||
f72fa41a75 | |||
adf4191066 | |||
d2de586cc9 | |||
dad5021870 | |||
ab3f993bb9 | |||
158fe2f9bb | |||
5970a6e2a2 | |||
5c8f024d12 | |||
428daa5323 | |||
4001af4d35 | |||
f1cec03dcf | |||
574ed72b95 | |||
480f5c2aac | |||
d4e502fdf5 | |||
05b2fb5ec1 | |||
bb92c4a967 | |||
b40caf12df | |||
8ebd2d14b4 | |||
445bc05b67 | |||
7538b2f860 | |||
367f86ecfb | |||
055ead54b5 | |||
df0232358b | |||
baa3ea6585 | |||
e75e2cf324 | |||
948b83a2b2 | |||
34e9af57fe | |||
94ae490284 | |||
690f263bac | |||
6280446450 | |||
7d87f86410 | |||
0d1201f972 | |||
78b23c4bd4 | |||
7fcfc48af2 | |||
611fd96e3a | |||
4671d4afb4 | |||
07c4ef986b | |||
7d64ec5066 | |||
ee6edec1d8 | |||
04cc7817ee | |||
9ac6511548 | |||
2eee53806a | |||
c5af79f176 | |||
0477862b73 | |||
5ef5213fae | |||
6a554ef45a | |||
f44175303b | |||
dfa80543b5 | |||
5f99887b50 | |||
2502a7cece | |||
77025cdb79 | |||
ce5f6d5d43 | |||
1893626e04 | |||
edb2aa2db5 | |||
9e539d0a0e | |||
a3088b7f79 | |||
b186e35b61 | |||
2a3933f141 | |||
2f2eec0d21 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2023.4.0
|
||||
current_version = 2023.4.1
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||
|
@ -6,3 +6,4 @@ dist/**
|
||||
build/**
|
||||
build_docs/**
|
||||
Dockerfile
|
||||
authentik/enterprise
|
||||
|
11
.github/ISSUE_TEMPLATE/bug_report.md
vendored
11
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,10 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
title: ""
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
@ -12,6 +11,7 @@ A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
@ -27,8 +27,9 @@ If applicable, add screenshots to help explain your problem.
|
||||
Output of docker-compose logs or kubectl logs respectively
|
||||
|
||||
**Version and Deployment (please complete the following information):**
|
||||
- authentik version: [e.g. 2021.8.5]
|
||||
- Deployment: [e.g. docker-compose, helm]
|
||||
|
||||
- authentik version: [e.g. 2021.8.5]
|
||||
- Deployment: [e.g. docker-compose, helm]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
5
.github/ISSUE_TEMPLATE/feature_request.md
vendored
5
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,10 +1,9 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
title: ""
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
|
10
.github/ISSUE_TEMPLATE/question.md
vendored
10
.github/ISSUE_TEMPLATE/question.md
vendored
@ -1,10 +1,9 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about a feature or specific configuration
|
||||
title: ''
|
||||
title: ""
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Describe your question/**
|
||||
@ -20,8 +19,9 @@ If applicable, add screenshots to help explain your problem.
|
||||
Output of docker-compose logs or kubectl logs respectively
|
||||
|
||||
**Version and Deployment (please complete the following information):**
|
||||
- authentik version: [e.g. 2021.8.5]
|
||||
- Deployment: [e.g. docker-compose, helm]
|
||||
|
||||
- authentik version: [e.g. 2021.8.5]
|
||||
- Deployment: [e.g. docker-compose, helm]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: 'Comment usage instructions on PRs'
|
||||
description: 'Comment usage instructions on PRs'
|
||||
name: "Comment usage instructions on PRs"
|
||||
description: "Comment usage instructions on PRs"
|
||||
|
||||
inputs:
|
||||
tag:
|
||||
@ -17,7 +17,7 @@ runs:
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
comment-author: "github-actions[bot]"
|
||||
body-includes: authentik PR Installation instructions
|
||||
- name: Create or update comment
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
|
10
.github/actions/docker-push-variables/action.yml
vendored
10
.github/actions/docker-push-variables/action.yml
vendored
@ -1,5 +1,5 @@
|
||||
name: 'Prepare docker environment variables'
|
||||
description: 'Prepare docker environment variables'
|
||||
name: "Prepare docker environment variables"
|
||||
description: "Prepare docker environment variables"
|
||||
|
||||
outputs:
|
||||
shouldBuild:
|
||||
@ -51,12 +51,14 @@ runs:
|
||||
version_family = ".".join(version.split(".")[:-1])
|
||||
safe_branch_name = branch_name.replace("refs/heads/", "").replace("/", "-")
|
||||
|
||||
sha = os.environ["GITHUB_SHA"] if not "${{ github.event.pull_request.head.sha }}" else "${{ github.event.pull_request.head.sha }}"
|
||||
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a+", encoding="utf-8") as _output:
|
||||
print("branchName=%s" % branch_name, file=_output)
|
||||
print("branchNameContainer=%s" % safe_branch_name, file=_output)
|
||||
print("timestamp=%s" % int(time()), file=_output)
|
||||
print("sha=%s" % os.environ["GITHUB_SHA"], file=_output)
|
||||
print("shortHash=%s" % os.environ["GITHUB_SHA"][:7], file=_output)
|
||||
print("sha=%s" % sha, file=_output)
|
||||
print("shortHash=%s" % sha[:7], file=_output)
|
||||
print("shouldBuild=%s" % should_build, file=_output)
|
||||
print("version=%s" % version, file=_output)
|
||||
print("versionFamily=%s" % version_family, file=_output)
|
||||
|
14
.github/actions/setup/action.yml
vendored
14
.github/actions/setup/action.yml
vendored
@ -1,5 +1,5 @@
|
||||
name: 'Setup authentik testing environment'
|
||||
description: 'Setup authentik testing environment'
|
||||
name: "Setup authentik testing environment"
|
||||
description: "Setup authentik testing environment"
|
||||
|
||||
inputs:
|
||||
postgresql_tag:
|
||||
@ -18,13 +18,13 @@ runs:
|
||||
- name: Setup python and restore poetry
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'poetry'
|
||||
python-version: "3.11"
|
||||
cache: "poetry"
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3.1.0
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- name: Setup dependencies
|
||||
shell: bash
|
||||
|
14
.github/actions/setup/docker-compose.yml
vendored
14
.github/actions/setup/docker-compose.yml
vendored
@ -1,23 +1,21 @@
|
||||
version: '3.7'
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
container_name: postgres
|
||||
image: library/postgres:${PSQL_TAG:-12}
|
||||
image: docker.io/library/postgres:${PSQL_TAG:-12}
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
|
||||
POSTGRES_DB: authentik
|
||||
ports:
|
||||
- 5432:5432
|
||||
- 5432:5432
|
||||
restart: always
|
||||
redis:
|
||||
container_name: redis
|
||||
image: library/redis
|
||||
image: docker.io/library/redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
- 6379:6379
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
|
120
.github/dependabot.yml
vendored
120
.github/dependabot.yml
vendored
@ -1,62 +1,62 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "ci:"
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "core:"
|
||||
- package-ecosystem: npm
|
||||
directory: "/web"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "web:"
|
||||
- package-ecosystem: npm
|
||||
directory: "/website"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "website:"
|
||||
- package-ecosystem: pip
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "core:"
|
||||
- package-ecosystem: docker
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "core:"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "ci:"
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "core:"
|
||||
- package-ecosystem: npm
|
||||
directory: "/web"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "web:"
|
||||
- package-ecosystem: npm
|
||||
directory: "/website"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "website:"
|
||||
- package-ecosystem: pip
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "core:"
|
||||
- package-ecosystem: docker
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "@goauthentik/core"
|
||||
commit-message:
|
||||
prefix: "core:"
|
||||
|
13
.github/pull_request_template.md
vendored
13
.github/pull_request_template.md
vendored
@ -5,15 +5,20 @@ Please check the [Contributing guidelines](https://github.com/goauthentik/authen
|
||||
-->
|
||||
|
||||
# Details
|
||||
* **Does this resolve an issue?**
|
||||
Resolves #
|
||||
|
||||
- **Does this resolve an issue?**
|
||||
Resolves #
|
||||
|
||||
## Changes
|
||||
|
||||
### New Features
|
||||
* Adds feature which does x, y, and z.
|
||||
|
||||
- Adds feature which does x, y, and z.
|
||||
|
||||
### Breaking Changes
|
||||
* Adds breaking change which causes \<issue\>.
|
||||
|
||||
- Adds breaking change which causes \<issue\>.
|
||||
|
||||
## Additional
|
||||
|
||||
Any further notes or comments you want to make.
|
||||
|
4
.github/transifex.yml
vendored
4
.github/transifex.yml
vendored
@ -6,11 +6,11 @@ git:
|
||||
source_language: en
|
||||
source_file: web/src/locales/en.po
|
||||
# path expression to translation files, must contain <lang> placeholder
|
||||
translation_files_expression: 'web/src/locales/<lang>.po'
|
||||
translation_files_expression: "web/src/locales/<lang>.po"
|
||||
- filter_type: file
|
||||
# all supported i18n types: https://docs.transifex.com/formats
|
||||
file_format: PO
|
||||
source_language: en
|
||||
source_file: locale/en/LC_MESSAGES/django.po
|
||||
# path expression to translation files, must contain <lang> placeholder
|
||||
translation_files_expression: 'locale/<lang>/LC_MESSAGES/django.po'
|
||||
translation_files_expression: "locale/<lang>/LC_MESSAGES/django.po"
|
||||
|
17
.github/workflows/ci-main.yml
vendored
17
.github/workflows/ci-main.yml
vendored
@ -23,13 +23,14 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- pylint
|
||||
- black
|
||||
- isort
|
||||
- bandit
|
||||
- pyright
|
||||
- pending-migrations
|
||||
- black
|
||||
- codespell
|
||||
- isort
|
||||
- pending-migrations
|
||||
- pylint
|
||||
- pyright
|
||||
- ruff
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -186,6 +187,8 @@ jobs:
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2.1.0
|
||||
- name: Set up Docker Buildx
|
||||
@ -211,6 +214,7 @@ jobs:
|
||||
push: ${{ steps.ev.outputs.shouldBuild == 'true' }}
|
||||
tags: |
|
||||
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.branchNameContainer }}
|
||||
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.sha }}
|
||||
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.shortHash }}
|
||||
build-args: |
|
||||
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}
|
||||
@ -227,6 +231,8 @@ jobs:
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2.1.0
|
||||
- name: Set up Docker Buildx
|
||||
@ -252,6 +258,7 @@ jobs:
|
||||
push: ${{ steps.ev.outputs.shouldBuild == 'true' }}
|
||||
tags: |
|
||||
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.branchNameContainer }}-arm64
|
||||
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.sha }}-arm64
|
||||
ghcr.io/goauthentik/dev-server:gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.shortHash }}-arm64
|
||||
build-args: |
|
||||
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}
|
||||
|
21
.github/workflows/ci-outpost.yml
vendored
21
.github/workflows/ci-outpost.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
go-version-file: "go.mod"
|
||||
- name: Prepare and generate API
|
||||
run: |
|
||||
# Create folder structure for go embeds
|
||||
@ -30,13 +30,14 @@ jobs:
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
args: --timeout 5000s
|
||||
skip-pkg-cache: true
|
||||
test-unittest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
go-version-file: "go.mod"
|
||||
- name: Generate API
|
||||
run: make gen-client-go
|
||||
- name: Go unittests
|
||||
@ -60,11 +61,11 @@ jobs:
|
||||
- proxy
|
||||
- ldap
|
||||
- radius
|
||||
arch:
|
||||
- "linux/amd64"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2.1.0
|
||||
- name: Set up Docker Buildx
|
||||
@ -94,7 +95,7 @@ jobs:
|
||||
build-args: |
|
||||
GIT_BUILD_HASH=${{ steps.ev.outputs.sha }}
|
||||
VERSION_FAMILY=${{ steps.ev.outputs.versionFamily }}
|
||||
platforms: ${{ matrix.arch }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
build-binary:
|
||||
timeout-minutes: 120
|
||||
@ -112,12 +113,14 @@ jobs:
|
||||
goarch: [amd64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
go-version-file: "go.mod"
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: "18"
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- name: Generate API
|
||||
@ -133,7 +136,3 @@ jobs:
|
||||
export GOOS=${{ matrix.goos }}
|
||||
export GOARCH=${{ matrix.goarch }}
|
||||
go build -tags=outpost_static_embed -v -o ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }} ./cmd/${{ matrix.type }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }}
|
||||
path: ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }}
|
||||
|
20
.github/workflows/ci-web.yml
vendored
20
.github/workflows/ci-web.yml
vendored
@ -17,8 +17,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- working-directory: web/
|
||||
run: npm ci
|
||||
@ -33,8 +33,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- working-directory: web/
|
||||
run: npm ci
|
||||
@ -49,8 +49,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- working-directory: web/
|
||||
run: npm ci
|
||||
@ -65,8 +65,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- working-directory: web/
|
||||
run: |
|
||||
@ -97,8 +97,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- working-directory: web/
|
||||
run: npm ci
|
||||
|
12
.github/workflows/ci-website.yml
vendored
12
.github/workflows/ci-website.yml
vendored
@ -17,8 +17,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
run: npm ci
|
||||
@ -31,8 +31,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
run: npm ci
|
||||
@ -52,8 +52,8 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
run: npm ci
|
||||
|
56
.github/workflows/codeql-analysis.yml
vendored
56
.github/workflows/codeql-analysis.yml
vendored
@ -2,12 +2,11 @@ name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, '*', next, version* ]
|
||||
branches: [main, "*", next, version*]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '30 6 * * 5'
|
||||
- cron: "30 6 * * 5"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
@ -21,40 +20,17 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go', 'javascript', 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
language: ["go", "javascript", "python"]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
2
.github/workflows/ghcr-retention.yml
vendored
2
.github/workflows/ghcr-retention.yml
vendored
@ -2,7 +2,7 @@ name: ghcr-retention
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # every day at midnight
|
||||
- cron: "0 0 * * *" # every day at midnight
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
12
.github/workflows/release-publish.yml
vendored
12
.github/workflows/release-publish.yml
vendored
@ -57,7 +57,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
go-version-file: "go.mod"
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2.1.0
|
||||
- name: Set up Docker Buildx
|
||||
@ -107,11 +107,11 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "^1.17"
|
||||
go-version-file: "go.mod"
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/package-lock.json
|
||||
- name: Build web
|
||||
working-directory: web/
|
||||
@ -173,5 +173,5 @@ jobs:
|
||||
SENTRY_PROJECT: authentik
|
||||
with:
|
||||
version: authentik@${{ steps.ev.outputs.version }}
|
||||
sourcemaps: './web/dist'
|
||||
url_prefix: '~/static/dist'
|
||||
sourcemaps: "./web/dist"
|
||||
url_prefix: "~/static/dist"
|
||||
|
2
.github/workflows/release-tag.yml
vendored
2
.github/workflows/release-tag.yml
vendored
@ -3,7 +3,7 @@ name: authentik-on-tag
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'version/*'
|
||||
- "version/*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
6
.github/workflows/translation-compile.yml
vendored
6
.github/workflows/translation-compile.yml
vendored
@ -1,12 +1,12 @@
|
||||
name: authentik-backend-translate-compile
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
paths:
|
||||
- '/locale/'
|
||||
- "/locale/"
|
||||
pull_request:
|
||||
paths:
|
||||
- '/locale/'
|
||||
- "/locale/"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
|
8
.github/workflows/web-api-publish.yml
vendored
8
.github/workflows/web-api-publish.yml
vendored
@ -1,9 +1,9 @@
|
||||
name: authentik-web-api-publish
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'schema.yml'
|
||||
- "schema.yml"
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
@ -14,8 +14,8 @@ jobs:
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: '18'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version: "20"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- name: Generate API Client
|
||||
run: make gen-client-ts
|
||||
- name: Publish package
|
||||
|
13
Dockerfile
13
Dockerfile
@ -1,5 +1,5 @@
|
||||
# Stage 1: Build website
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:18 as website-builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:20 as website-builder
|
||||
|
||||
COPY ./website /work/website/
|
||||
COPY ./blueprints /work/blueprints/
|
||||
@ -10,7 +10,7 @@ WORKDIR /work/website
|
||||
RUN npm ci && npm run build-docs-only
|
||||
|
||||
# Stage 2: Build webui
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:18 as web-builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:20 as web-builder
|
||||
|
||||
COPY ./web /work/web/
|
||||
COPY ./website /work/website/
|
||||
@ -83,7 +83,9 @@ RUN apt-get update && \
|
||||
# Required for runtime
|
||||
apt-get install -y --no-install-recommends libxmlsec1-openssl libmaxminddb0 && \
|
||||
# Required for bootstrap & healtcheck
|
||||
apt-get install -y --no-install-recommends curl runit && \
|
||||
apt-get install -y --no-install-recommends runit && \
|
||||
# Required for outposts
|
||||
apt-get install -y --no-install-recommends openssh-client && \
|
||||
pip install --no-cache-dir -r /requirements.txt && \
|
||||
apt-get remove --purge -y build-essential pkg-config libxmlsec1-dev && \
|
||||
apt-get autoremove --purge -y && \
|
||||
@ -91,8 +93,9 @@ RUN apt-get update && \
|
||||
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/ && \
|
||||
adduser --system --no-create-home --uid 1000 --group --home /authentik authentik && \
|
||||
mkdir -p /certs /media /blueprints && \
|
||||
mkdir -p /authentik/.ssh && \
|
||||
chown authentik:authentik /certs /media /authentik/.ssh
|
||||
chown authentik:authentik /certs /media && \
|
||||
chmod g+w /etc/ssh/ssh_config.d/ && \
|
||||
chgrp authentik /etc/ssh/ssh_config.d/
|
||||
|
||||
COPY ./authentik/ /authentik
|
||||
COPY ./pyproject.toml /
|
||||
|
9
LICENSE
9
LICENSE
@ -1,6 +1,11 @@
|
||||
MIT License
|
||||
Copyright (c) 2023 Jens Langhammer
|
||||
|
||||
Copyright (c) 2022 Jens Langhammer
|
||||
Portions of this software are licensed as follows:
|
||||
* All content residing under the "website/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
|
||||
* All content that resides under the "authentik/enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "authentik/enterprise/LICENSE".
|
||||
* All client-side JavaScript (when served directly or after being compiled, arranged, augmented, or combined), is licensed under the "MIT Expat" license.
|
||||
* All third party components incorporated into the authentik are licensed under the original license provided by the owner of the applicable component.
|
||||
* Content outside of the above mentioned directories or restrictions above is available under the "MIT" license as defined below.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
14
Makefile
14
Makefile
@ -3,6 +3,7 @@ PWD = $(shell pwd)
|
||||
UID = $(shell id -u)
|
||||
GID = $(shell id -g)
|
||||
NPM_VERSION = $(shell python -m scripts.npm_version)
|
||||
PY_SOURCES = authentik tests scripts lifecycle
|
||||
|
||||
CODESPELL_ARGS = -D - -D .github/codespell-dictionary.txt \
|
||||
-I .github/codespell-words.txt \
|
||||
@ -38,13 +39,14 @@ test:
|
||||
coverage report
|
||||
|
||||
lint-fix:
|
||||
isort authentik tests scripts lifecycle
|
||||
black authentik tests scripts lifecycle
|
||||
isort authentik $(PY_SOURCES)
|
||||
black authentik $(PY_SOURCES)
|
||||
ruff authentik $(PY_SOURCES)
|
||||
codespell -w $(CODESPELL_ARGS)
|
||||
|
||||
lint:
|
||||
pylint authentik tests lifecycle
|
||||
bandit -r authentik tests lifecycle -x node_modules
|
||||
pylint $(PY_SOURCES)
|
||||
bandit -r $(PY_SOURCES) -x node_modules
|
||||
golangci-lint run -v
|
||||
|
||||
migrate:
|
||||
@ -171,7 +173,6 @@ website-watch:
|
||||
|
||||
# These targets are use by GitHub actions to allow usage of matrix
|
||||
# which makes the YAML File a lot smaller
|
||||
PY_SOURCES=authentik tests lifecycle
|
||||
ci--meta-debug:
|
||||
python -V
|
||||
node --version
|
||||
@ -182,6 +183,9 @@ ci-pylint: ci--meta-debug
|
||||
ci-black: ci--meta-debug
|
||||
black --check $(PY_SOURCES)
|
||||
|
||||
ci-ruff: ci--meta-debug
|
||||
ruff check $(PY_SOURCES)
|
||||
|
||||
ci-codespell: ci--meta-debug
|
||||
codespell $(CODESPELL_ARGS) -s
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
from os import environ
|
||||
from typing import Optional
|
||||
|
||||
__version__ = "2023.4.0"
|
||||
__version__ = "2023.4.1"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@ class Capabilities(models.TextChoices):
|
||||
CAN_GEO_IP = "can_geo_ip"
|
||||
CAN_IMPERSONATE = "can_impersonate"
|
||||
CAN_DEBUG = "can_debug"
|
||||
IS_ENTERPRISE = "is_enterprise"
|
||||
|
||||
|
||||
class ErrorReportingConfigSerializer(PassiveSerializer):
|
||||
@ -70,6 +71,8 @@ class ConfigView(APIView):
|
||||
caps.append(Capabilities.CAN_IMPERSONATE)
|
||||
if settings.DEBUG: # pragma: no cover
|
||||
caps.append(Capabilities.CAN_DEBUG)
|
||||
if "authentik.enterprise" in settings.INSTALLED_APPS:
|
||||
caps.append(Capabilities.IS_ENTERPRISE)
|
||||
return caps
|
||||
|
||||
def get_config(self) -> ConfigSerializer:
|
||||
|
@ -6,7 +6,6 @@ from pathlib import Path
|
||||
import django.contrib.postgres.fields
|
||||
from dacite.core import from_dict
|
||||
from django.apps.registry import Apps
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from yaml import load
|
||||
@ -15,7 +14,7 @@ from authentik.blueprints.v1.labels import LABEL_AUTHENTIK_SYSTEM
|
||||
from authentik.lib.config import CONFIG
|
||||
|
||||
|
||||
def check_blueprint_v1_file(BlueprintInstance: type["BlueprintInstance"], path: Path):
|
||||
def check_blueprint_v1_file(BlueprintInstance: type, path: Path):
|
||||
"""Check if blueprint should be imported"""
|
||||
from authentik.blueprints.models import BlueprintInstanceStatus
|
||||
from authentik.blueprints.v1.common import BlueprintLoader, BlueprintMetadata
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from authentik.lib.generators import generate_id
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
|
45
authentik/enterprise/LICENSE
Normal file
45
authentik/enterprise/LICENSE
Normal file
@ -0,0 +1,45 @@
|
||||
The authentik Enterprise Edition (EE) license (the “EE License”)
|
||||
Copyright (c) 2022-present Authentik Security Inc.
|
||||
|
||||
With regard to the authentik Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the Authentik Subscription Terms of Service, available
|
||||
at https://goauthentik.io/legal/terms (the "EE Terms"), or other
|
||||
agreement governing the use of the Software, as agreed by you and authentik Security Inc,
|
||||
and otherwise have a valid authentik Enterprise Edition subscription for the
|
||||
correct number of user seats. Subject to the foregoing sentence, you are free to
|
||||
modify this Software and publish patches to the Software. You agree that Authentik
|
||||
Security Inc. and/or its licensors (as applicable) retain all right, title and interest
|
||||
in and to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid authentik Enterprise Edition subscription for the correct
|
||||
number of user seats. Notwithstanding the foregoing, you may copy and modify
|
||||
the Software for development and testing purposes, without requiring a
|
||||
subscription. You agree that Authentik Security Inc. and/or its
|
||||
licensors (as applicable) retain all right, title and interest in
|
||||
and to all such modifications. You are not granted any other rights
|
||||
beyond what is expressly stated herein. Subject to the
|
||||
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
This EE License applies only to the part of this Software that is not
|
||||
distributed as part of authentik Open Source (OSS). Any part of this Software
|
||||
distributed as part of authentik OSS or is served client-side as an image, font,
|
||||
cascading stylesheet (CSS), file which produces or is compiled, arranged,
|
||||
augmented, or combined into client-side JavaScript, in whole or in part, is
|
||||
copyrighted under the MIT license. The full text of this EE License shall
|
||||
be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the authentik Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
11
authentik/enterprise/apps.py
Normal file
11
authentik/enterprise/apps.py
Normal file
@ -0,0 +1,11 @@
|
||||
"""Enterprise app config"""
|
||||
from authentik.blueprints.apps import ManagedAppConfig
|
||||
|
||||
|
||||
class AuthentikEnterpriseConfig(ManagedAppConfig):
|
||||
"""Enterprise app config"""
|
||||
|
||||
name = "authentik.enterprise"
|
||||
label = "authentik_enterprise"
|
||||
verbose_name = "authentik Enterprise"
|
||||
default = True
|
1
authentik/enterprise/settings.py
Normal file
1
authentik/enterprise/settings.py
Normal file
@ -0,0 +1 @@
|
||||
"""Enterprise additional settings"""
|
@ -11,7 +11,6 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
import authentik.events.models
|
||||
import authentik.lib.models
|
||||
from authentik.events.models import EventAction, NotificationSeverity, TransportMode
|
||||
from authentik.lib.migrations import progress_bar
|
||||
|
||||
|
||||
|
@ -57,10 +57,6 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
|
||||
LOGGER.debug("e(trigger): attempting to prevent infinite loop", trigger=trigger)
|
||||
return
|
||||
|
||||
if not trigger.group:
|
||||
LOGGER.debug("e(trigger): trigger has no group", trigger=trigger)
|
||||
return
|
||||
|
||||
LOGGER.debug("e(trigger): checking if trigger applies", trigger=trigger)
|
||||
try:
|
||||
user = User.objects.filter(pk=event.user.get("pk")).first() or get_anonymous_user()
|
||||
@ -77,6 +73,10 @@ def event_trigger_handler(event_uuid: str, trigger_name: str):
|
||||
if not result.passing:
|
||||
return
|
||||
|
||||
if not trigger.group:
|
||||
LOGGER.debug("e(trigger): trigger has no group", trigger=trigger)
|
||||
return
|
||||
|
||||
LOGGER.debug("e(trigger): event trigger matched", trigger=trigger)
|
||||
# Create the notification objects
|
||||
for transport in trigger.transports.all():
|
||||
|
@ -67,7 +67,7 @@ def sentry_init(**sentry_init_kwargs):
|
||||
ArgvIntegration(),
|
||||
StdlibIntegration(),
|
||||
DjangoIntegration(transaction_style="function_name"),
|
||||
CeleryIntegration(monitor_beat_tasks=True),
|
||||
CeleryIntegration(),
|
||||
RedisIntegration(),
|
||||
ThreadingIntegration(propagate_hub=True),
|
||||
SocketIntegration(),
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Docker controller"""
|
||||
from subprocess import SubprocessError # nosec
|
||||
from time import sleep
|
||||
from typing import Optional
|
||||
from urllib.parse import urlparse
|
||||
@ -9,11 +10,9 @@ from docker import DockerClient as UpstreamDockerClient
|
||||
from docker.errors import DockerException, NotFound
|
||||
from docker.models.containers import Container
|
||||
from docker.utils.utils import kwargs_from_env
|
||||
from paramiko.ssh_exception import SSHException
|
||||
from structlog.stdlib import get_logger
|
||||
from yaml import safe_dump
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||
from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException
|
||||
from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException
|
||||
@ -59,8 +58,9 @@ class DockerClient(UpstreamDockerClient, BaseClient):
|
||||
super().__init__(
|
||||
base_url=connection.url,
|
||||
tls=tls_config,
|
||||
use_ssh_client=True,
|
||||
)
|
||||
except SSHException as exc:
|
||||
except SubprocessError as exc:
|
||||
if self.ssh:
|
||||
self.ssh.cleanup()
|
||||
raise ServiceConnectionInvalid(exc) from exc
|
||||
|
@ -22,7 +22,7 @@ from kubernetes.client import (
|
||||
V1SecurityContext,
|
||||
)
|
||||
|
||||
from authentik import __version__, get_full_version
|
||||
from authentik import get_full_version
|
||||
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||
from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
|
||||
from authentik.outposts.controllers.k8s.triggers import NeedsUpdate
|
||||
|
@ -7,8 +7,7 @@ from docker.errors import DockerException
|
||||
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
|
||||
HEADER = "### Managed by authentik"
|
||||
FOOTER = "### End Managed by authentik"
|
||||
SSH_CONFIG_DIR = Path("/etc/ssh/ssh_config.d/")
|
||||
|
||||
|
||||
def opener(path, flags):
|
||||
@ -28,70 +27,54 @@ class DockerInlineSSH:
|
||||
|
||||
key_path: str
|
||||
config_path: Path
|
||||
header: str
|
||||
|
||||
def __init__(self, host: str, keypair: CertificateKeyPair) -> None:
|
||||
self.host = host
|
||||
self.keypair = keypair
|
||||
self.config_path = Path("~/.ssh/config").expanduser()
|
||||
if self.config_path.exists() and HEADER not in self.config_path.read_text(encoding="utf-8"):
|
||||
# SSH Config file already exists and there's no header from us, meaning that it's
|
||||
# been externally mapped into the container for more complex configs
|
||||
raise SSHManagedExternallyException(
|
||||
"SSH Config exists and does not contain authentik header"
|
||||
)
|
||||
self.config_path = SSH_CONFIG_DIR / Path(self.host + ".conf")
|
||||
with open(self.config_path, "w", encoding="utf-8") as _config:
|
||||
if not _config.writable():
|
||||
# SSH Config file already exists and there's no header from us, meaning that it's
|
||||
# been externally mapped into the container for more complex configs
|
||||
raise SSHManagedExternallyException(
|
||||
"SSH Config exists and does not contain authentik header"
|
||||
)
|
||||
if not self.keypair:
|
||||
raise DockerException("keypair must be set for SSH connections")
|
||||
self.header = f"{HEADER} - {self.host}\n"
|
||||
|
||||
def write_config(self, key_path: str) -> bool:
|
||||
def write_config(self, key_path: str):
|
||||
"""Update the local user's ssh config file"""
|
||||
with open(self.config_path, "a+", encoding="utf-8") as ssh_config:
|
||||
if self.header in ssh_config.readlines():
|
||||
return False
|
||||
with open(self.config_path, "w", encoding="utf-8") as ssh_config:
|
||||
ssh_config.writelines(
|
||||
[
|
||||
self.header,
|
||||
f"Host {self.host}\n",
|
||||
f" IdentityFile {key_path}\n",
|
||||
f" IdentityFile {str(key_path)}\n",
|
||||
" StrictHostKeyChecking No\n",
|
||||
" UserKnownHostsFile /dev/null\n",
|
||||
f"{FOOTER}\n",
|
||||
"\n",
|
||||
]
|
||||
)
|
||||
return True
|
||||
|
||||
def write_key(self):
|
||||
def write_key(self) -> Path:
|
||||
"""Write keypair's private key to a temporary file"""
|
||||
path = Path(gettempdir(), f"{self.keypair.pk}_private.pem")
|
||||
with open(path, "w", encoding="utf8", opener=opener) as _file:
|
||||
_file.write(self.keypair.key_data)
|
||||
return str(path)
|
||||
return path
|
||||
|
||||
def write(self):
|
||||
"""Write keyfile and update ssh config"""
|
||||
self.key_path = self.write_key()
|
||||
was_written = self.write_config(self.key_path)
|
||||
if not was_written:
|
||||
try:
|
||||
self.write_config(self.key_path)
|
||||
except OSError:
|
||||
self.cleanup()
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup when we're done"""
|
||||
try:
|
||||
os.unlink(self.key_path)
|
||||
with open(self.config_path, "r", encoding="utf-8") as ssh_config:
|
||||
start = 0
|
||||
end = 0
|
||||
lines = ssh_config.readlines()
|
||||
for idx, line in enumerate(lines):
|
||||
if line == self.header:
|
||||
start = idx
|
||||
if start != 0 and line == f"{FOOTER}\n":
|
||||
end = idx
|
||||
with open(self.config_path, "w+", encoding="utf-8") as ssh_config:
|
||||
lines = lines[:start] + lines[end + 2 :]
|
||||
ssh_config.writelines(lines)
|
||||
os.unlink(self.config_path)
|
||||
except OSError:
|
||||
# If we fail deleting a file it doesn't matter that much
|
||||
# since we're just in a container
|
||||
|
@ -59,6 +59,7 @@ class TestPasswordPolicyFlow(FlowTestCase):
|
||||
"label": "PASSWORD_LABEL",
|
||||
"order": 0,
|
||||
"placeholder": "PASSWORD_PLACEHOLDER",
|
||||
"initial_value": "",
|
||||
"required": True,
|
||||
"type": "password",
|
||||
"sub_text": "",
|
||||
|
@ -1,10 +1,8 @@
|
||||
# Generated by Django 3.1 on 2020-08-18 15:59
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.apps.registry import Apps
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
import authentik.core.models
|
||||
import authentik.lib.generators
|
||||
|
@ -68,7 +68,7 @@ from authentik.stages.consent.stage import (
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
PLAN_CONTEXT_PARAMS = "params"
|
||||
PLAN_CONTEXT_PARAMS = "goauthentik.io/providers/oauth2/params"
|
||||
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
|
||||
|
||||
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
|
||||
|
@ -8,7 +8,7 @@ from authentik.flows.stage import ChallengeStageView
|
||||
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||
from authentik.providers.oauth2.models import DeviceToken
|
||||
|
||||
PLAN_CONTEXT_DEVICE = "device"
|
||||
PLAN_CONTEXT_DEVICE = "goauthentik.io/providers/oauth2/device"
|
||||
|
||||
|
||||
class OAuthDeviceCodeFinishChallenge(Challenge):
|
||||
|
@ -29,9 +29,6 @@ from authentik.providers.oauth2.utils import cors_allow
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
PLAN_CONTEXT_PARAMS = "params"
|
||||
PLAN_CONTEXT_SCOPES = "scopes"
|
||||
|
||||
|
||||
class ProviderInfoView(View):
|
||||
"""OpenID-compliant Provider Info"""
|
||||
|
@ -492,3 +492,12 @@ if DEBUG:
|
||||
INSTALLED_APPS.append("authentik.core")
|
||||
|
||||
CONFIG.log("info", "Booting authentik", version=__version__)
|
||||
|
||||
# Attempt to load enterprise app, if available
|
||||
try:
|
||||
importlib.import_module("authentik.enterprise.apps")
|
||||
CONFIG.log("info", "Enabled authentik enterprise")
|
||||
INSTALLED_APPS.append("authentik.enterprise")
|
||||
_update_settings("authentik.enterprise.settings")
|
||||
except ImportError:
|
||||
pass
|
||||
|
@ -3,8 +3,6 @@
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
import authentik.lib.generators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
|
@ -40,11 +40,7 @@ from authentik.sources.saml.models import SAMLBindingTypes, SAMLSource
|
||||
from authentik.sources.saml.processors.metadata import MetadataProcessor
|
||||
from authentik.sources.saml.processors.request import RequestProcessor
|
||||
from authentik.sources.saml.processors.response import ResponseProcessor
|
||||
from authentik.stages.consent.stage import (
|
||||
PLAN_CONTEXT_CONSENT_HEADER,
|
||||
PLAN_CONTEXT_CONSENT_TITLE,
|
||||
ConsentStageView,
|
||||
)
|
||||
from authentik.stages.consent.stage import PLAN_CONTEXT_CONSENT_HEADER, ConsentStageView
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
@ -128,7 +124,6 @@ class InitiateView(View):
|
||||
injected_stages = []
|
||||
plan_kwargs = {
|
||||
PLAN_CONTEXT_TITLE: f"Redirecting to {source.name}...",
|
||||
PLAN_CONTEXT_CONSENT_TITLE: f"Redirecting to {source.name}...",
|
||||
PLAN_CONTEXT_ATTRS: {
|
||||
"SAMLRequest": saml_request,
|
||||
"RelayState": relay_state,
|
||||
|
@ -10,7 +10,6 @@ from duo_client.admin import Admin
|
||||
from duo_client.auth import Auth
|
||||
from rest_framework.serializers import BaseSerializer, Serializer
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.core.types import UserSettingSerializer
|
||||
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
|
||||
from authentik.lib.models import SerializerModel
|
||||
|
@ -33,7 +33,6 @@ from authentik.stages.authenticator_validate.models import AuthenticatorValidate
|
||||
from authentik.stages.authenticator_webauthn.models import UserVerification, WebAuthnDevice
|
||||
from authentik.stages.authenticator_webauthn.stage import SESSION_KEY_WEBAUTHN_CHALLENGE
|
||||
from authentik.stages.authenticator_webauthn.utils import get_origin, get_rp_id
|
||||
from authentik.stages.consent.stage import PLAN_CONTEXT_CONSENT_TITLE
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
@ -175,8 +174,6 @@ def validate_challenge_duo(device_pk: int, stage_view: StageView, user: User) ->
|
||||
pushinfo = {
|
||||
__("Domain"): stage_view.request.get_host(),
|
||||
}
|
||||
if PLAN_CONTEXT_CONSENT_TITLE in stage_view.executor.plan.context:
|
||||
pushinfo[__("Title")] = stage_view.executor.plan.context[PLAN_CONTEXT_CONSENT_TITLE]
|
||||
if SESSION_KEY_APPLICATION_PRE in stage_view.request.session:
|
||||
pushinfo[__("Application")] = stage_view.request.session.get(
|
||||
SESSION_KEY_APPLICATION_PRE, Application()
|
||||
|
@ -14,7 +14,6 @@ from rest_framework.serializers import ValidationError
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.models import User
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.events.utils import cleanse_dict, sanitize_dict
|
||||
from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUserInfoChallenge
|
||||
from authentik.flows.exceptions import FlowSkipStageException
|
||||
from authentik.flows.models import FlowDesignation, NotConfiguredAction, Stage
|
||||
@ -382,13 +381,9 @@ class AuthenticatorValidateStageView(ChallengeStageView):
|
||||
self.logger.debug("Set user from user-less flow", user=webauthn_device.user)
|
||||
self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] = webauthn_device.user
|
||||
self.executor.plan.context[PLAN_CONTEXT_METHOD] = "auth_webauthn_pwl"
|
||||
self.executor.plan.context[PLAN_CONTEXT_METHOD_ARGS] = cleanse_dict(
|
||||
sanitize_dict(
|
||||
{
|
||||
"device": webauthn_device,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.executor.plan.context[PLAN_CONTEXT_METHOD_ARGS] = {
|
||||
"device": webauthn_device,
|
||||
}
|
||||
return self.set_valid_mfa_cookie(response.device)
|
||||
|
||||
def cleanup(self):
|
||||
|
@ -19,7 +19,6 @@ from authentik.lib.utils.time import timedelta_from_string
|
||||
from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent
|
||||
|
||||
PLAN_CONTEXT_CONSENT = "consent"
|
||||
PLAN_CONTEXT_CONSENT_TITLE = "consent_title"
|
||||
PLAN_CONTEXT_CONSENT_HEADER = "consent_header"
|
||||
PLAN_CONTEXT_CONSENT_PERMISSIONS = "consent_permissions"
|
||||
PLAN_CONTEXT_CONSENT_EXTRA_PERMISSIONS = "consent_additional_permissions"
|
||||
@ -59,8 +58,6 @@ class ConsentStageView(ChallengeStageView):
|
||||
),
|
||||
"token": token,
|
||||
}
|
||||
if PLAN_CONTEXT_CONSENT_TITLE in self.executor.plan.context:
|
||||
data["title"] = self.executor.plan.context[PLAN_CONTEXT_CONSENT_TITLE]
|
||||
if PLAN_CONTEXT_CONSENT_HEADER in self.executor.plan.context:
|
||||
data["header_text"] = self.executor.plan.context[PLAN_CONTEXT_CONSENT_HEADER]
|
||||
challenge = ConsentChallenge(data=data)
|
||||
|
@ -4,7 +4,7 @@ from django.apps.registry import Apps
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
from authentik.stages.password import BACKEND_APP_PASSWORD, BACKEND_INBUILT
|
||||
from authentik.stages.password import BACKEND_APP_PASSWORD
|
||||
|
||||
|
||||
def update_default_backends(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Generated by Django 3.2.6 on 2021-08-23 14:34
|
||||
import django.contrib.postgres.fields
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
from authentik.stages.password import BACKEND_INBUILT
|
||||
|
@ -57,10 +57,12 @@ class PromptSerializer(ModelSerializer):
|
||||
"type",
|
||||
"required",
|
||||
"placeholder",
|
||||
"initial_value",
|
||||
"order",
|
||||
"promptstage_set",
|
||||
"sub_text",
|
||||
"placeholder_expression",
|
||||
"initial_value_expression",
|
||||
]
|
||||
|
||||
|
||||
|
@ -0,0 +1,53 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-24 17:32
|
||||
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
|
||||
def migrate_placeholder_expressions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||
from authentik.stages.prompt.models import CHOICE_FIELDS
|
||||
|
||||
db_alias = schema_editor.connection.alias
|
||||
Prompt = apps.get_model("authentik_stages_prompt", "prompt")
|
||||
|
||||
for prompt in Prompt.objects.using(db_alias).all():
|
||||
if not prompt.placeholder_expression or prompt.type in CHOICE_FIELDS:
|
||||
continue
|
||||
|
||||
prompt.initial_value = prompt.placeholder
|
||||
prompt.initial_value_expression = True
|
||||
prompt.placeholder = ""
|
||||
prompt.placeholder_expression = False
|
||||
prompt.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("authentik_stages_prompt", "0010_alter_prompt_placeholder_alter_prompt_type"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="prompt",
|
||||
name="initial_value",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Optionally pre-fill the input with an initial value. When creating a fixed choice field, enable interpreting as expression and return a list to return multiple default choices.",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="prompt",
|
||||
name="initial_value_expression",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="prompt",
|
||||
name="placeholder",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Optionally provide a short hint that describes the expected input value. When creating a fixed choice field, enable interpreting as expression and return a list to return multiple choices.",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(code=migrate_placeholder_expressions),
|
||||
]
|
@ -29,6 +29,8 @@ from authentik.flows.models import Stage
|
||||
from authentik.lib.models import SerializerModel
|
||||
from authentik.policies.models import Policy
|
||||
|
||||
CHOICES_CONTEXT_SUFFIX = "__choices"
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
@ -119,15 +121,25 @@ class Prompt(SerializerModel):
|
||||
placeholder = models.TextField(
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"When creating a Radio Button Group or Dropdown, enable interpreting as "
|
||||
"Optionally provide a short hint that describes the expected input value. "
|
||||
"When creating a fixed choice field, enable interpreting as "
|
||||
"expression and return a list to return multiple choices."
|
||||
),
|
||||
)
|
||||
initial_value = models.TextField(
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"Optionally pre-fill the input with an initial value. "
|
||||
"When creating a fixed choice field, enable interpreting as "
|
||||
"expression and return a list to return multiple default choices."
|
||||
),
|
||||
)
|
||||
sub_text = models.TextField(blank=True, default="")
|
||||
|
||||
order = models.IntegerField(default=0)
|
||||
|
||||
placeholder_expression = models.BooleanField(default=False)
|
||||
initial_value_expression = models.BooleanField(default=False)
|
||||
|
||||
@property
|
||||
def serializer(self) -> Type[BaseSerializer]:
|
||||
@ -148,8 +160,8 @@ class Prompt(SerializerModel):
|
||||
|
||||
raw_choices = self.placeholder
|
||||
|
||||
if self.field_key in prompt_context:
|
||||
raw_choices = prompt_context[self.field_key]
|
||||
if self.field_key + CHOICES_CONTEXT_SUFFIX in prompt_context:
|
||||
raw_choices = prompt_context[self.field_key + CHOICES_CONTEXT_SUFFIX]
|
||||
elif self.placeholder_expression:
|
||||
evaluator = PropertyMappingEvaluator(
|
||||
self, user, request, prompt_context=prompt_context, dry_run=dry_run
|
||||
@ -184,16 +196,9 @@ class Prompt(SerializerModel):
|
||||
) -> str:
|
||||
"""Get fully interpolated placeholder"""
|
||||
if self.type in CHOICE_FIELDS:
|
||||
# Make sure to return a valid choice as placeholder
|
||||
choices = self.get_choices(prompt_context, user, request, dry_run=dry_run)
|
||||
if not choices:
|
||||
return ""
|
||||
return choices[0]
|
||||
|
||||
if self.field_key in prompt_context:
|
||||
# We don't want to parse this as an expression since a user will
|
||||
# be able to control the input
|
||||
return prompt_context[self.field_key]
|
||||
# Choice fields use the placeholder to define all valid choices.
|
||||
# Therefore their actual placeholder is always blank
|
||||
return ""
|
||||
|
||||
if self.placeholder_expression:
|
||||
evaluator = PropertyMappingEvaluator(
|
||||
@ -211,6 +216,47 @@ class Prompt(SerializerModel):
|
||||
raise wrapped from exc
|
||||
return self.placeholder
|
||||
|
||||
def get_initial_value(
|
||||
self,
|
||||
prompt_context: dict,
|
||||
user: User,
|
||||
request: HttpRequest,
|
||||
dry_run: Optional[bool] = False,
|
||||
) -> str:
|
||||
"""Get fully interpolated initial value"""
|
||||
|
||||
if self.field_key in prompt_context:
|
||||
# We don't want to parse this as an expression since a user will
|
||||
# be able to control the input
|
||||
value = prompt_context[self.field_key]
|
||||
elif self.initial_value_expression:
|
||||
evaluator = PropertyMappingEvaluator(
|
||||
self, user, request, prompt_context=prompt_context, dry_run=dry_run
|
||||
)
|
||||
try:
|
||||
value = evaluator.evaluate(self.initial_value)
|
||||
except Exception as exc: # pylint:disable=broad-except
|
||||
wrapped = PropertyMappingExpressionException(str(exc))
|
||||
LOGGER.warning(
|
||||
"failed to evaluate prompt initial value",
|
||||
exc=wrapped,
|
||||
)
|
||||
if dry_run:
|
||||
raise wrapped from exc
|
||||
value = self.initial_value
|
||||
else:
|
||||
value = self.initial_value
|
||||
|
||||
if self.type in CHOICE_FIELDS:
|
||||
# Ensure returned value is a valid choice
|
||||
choices = self.get_choices(prompt_context, user, request)
|
||||
if not choices:
|
||||
return ""
|
||||
if value not in choices:
|
||||
return choices[0]
|
||||
|
||||
return value
|
||||
|
||||
def field(self, default: Optional[Any], choices: Optional[list[Any]] = None) -> CharField:
|
||||
"""Get field type for Challenge and response. Choices are only valid for CHOICE_FIELDS."""
|
||||
field_class = CharField
|
||||
|
@ -38,6 +38,7 @@ class StagePromptSerializer(PassiveSerializer):
|
||||
type = ChoiceField(choices=FieldTypes.choices)
|
||||
required = BooleanField()
|
||||
placeholder = CharField(allow_blank=True)
|
||||
initial_value = CharField(allow_blank=True)
|
||||
order = IntegerField()
|
||||
sub_text = CharField(allow_blank=True)
|
||||
choices = ListField(child=CharField(allow_blank=True), allow_empty=True, allow_null=True)
|
||||
@ -76,7 +77,7 @@ class PromptChallengeResponse(ChallengeResponse):
|
||||
choices = field.get_choices(
|
||||
plan.context.get(PLAN_CONTEXT_PROMPT, {}), user, self.request
|
||||
)
|
||||
current = field.get_placeholder(
|
||||
current = field.get_initial_value(
|
||||
plan.context.get(PLAN_CONTEXT_PROMPT, {}), user, self.request
|
||||
)
|
||||
self.fields[field.field_key] = field.field(current, choices)
|
||||
@ -197,8 +198,9 @@ class PromptStageView(ChallengeStageView):
|
||||
serializers = []
|
||||
for field in fields:
|
||||
data = StagePromptSerializer(field).data
|
||||
# Ensure all choices and placeholders are str, as otherwise further in
|
||||
# we can fail serializer validation if we return some types such as bool
|
||||
# Ensure all choices, placeholders and initial values are str, as
|
||||
# otherwise further in we can fail serializer validation if we return
|
||||
# some types such as bool
|
||||
choices = field.get_choices(context, self.get_pending_user(), self.request, dry_run)
|
||||
if choices:
|
||||
data["choices"] = [str(choice) for choice in choices]
|
||||
@ -207,6 +209,9 @@ class PromptStageView(ChallengeStageView):
|
||||
data["placeholder"] = str(
|
||||
field.get_placeholder(context, self.get_pending_user(), self.request, dry_run)
|
||||
)
|
||||
data["initial_value"] = str(
|
||||
field.get_initial_value(context, self.get_pending_user(), self.request, dry_run)
|
||||
)
|
||||
serializers.append(data)
|
||||
return serializers
|
||||
|
||||
|
@ -22,6 +22,7 @@ from authentik.stages.prompt.stage import (
|
||||
)
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
class TestPromptStage(FlowTestCase):
|
||||
"""Prompt tests"""
|
||||
|
||||
@ -37,6 +38,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.USERNAME,
|
||||
required=True,
|
||||
placeholder="USERNAME_PLACEHOLDER",
|
||||
initial_value="akuser",
|
||||
)
|
||||
text_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -45,6 +47,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.TEXT,
|
||||
required=True,
|
||||
placeholder="TEXT_PLACEHOLDER",
|
||||
initial_value="some text",
|
||||
)
|
||||
text_area_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -53,6 +56,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.TEXT_AREA,
|
||||
required=True,
|
||||
placeholder="TEXT_AREA_PLACEHOLDER",
|
||||
initial_value="some text",
|
||||
)
|
||||
email_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -61,6 +65,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.EMAIL,
|
||||
required=True,
|
||||
placeholder="EMAIL_PLACEHOLDER",
|
||||
initial_value="email@example.com",
|
||||
)
|
||||
password_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -69,6 +74,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.PASSWORD,
|
||||
required=True,
|
||||
placeholder="PASSWORD_PLACEHOLDER",
|
||||
initial_value="supersecurepassword",
|
||||
)
|
||||
password2_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -77,6 +83,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.PASSWORD,
|
||||
required=True,
|
||||
placeholder="PASSWORD_PLACEHOLDER",
|
||||
initial_value="supersecurepassword",
|
||||
)
|
||||
number_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -85,6 +92,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.NUMBER,
|
||||
required=True,
|
||||
placeholder="NUMBER_PLACEHOLDER",
|
||||
initial_value="42",
|
||||
)
|
||||
hidden_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -92,6 +100,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.HIDDEN,
|
||||
required=True,
|
||||
placeholder="HIDDEN_PLACEHOLDER",
|
||||
initial_value="something idk",
|
||||
)
|
||||
static_prompt = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -99,6 +108,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.STATIC,
|
||||
required=True,
|
||||
placeholder="static",
|
||||
initial_value="something idk",
|
||||
)
|
||||
radio_button_group = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -106,6 +116,7 @@ class TestPromptStage(FlowTestCase):
|
||||
type=FieldTypes.RADIO_BUTTON_GROUP,
|
||||
required=True,
|
||||
placeholder="test",
|
||||
initial_value="test",
|
||||
)
|
||||
dropdown = Prompt.objects.create(
|
||||
name=generate_id(),
|
||||
@ -137,9 +148,9 @@ class TestPromptStage(FlowTestCase):
|
||||
password_prompt.field_key: "test",
|
||||
password2_prompt.field_key: "test",
|
||||
number_prompt.field_key: 3,
|
||||
hidden_prompt.field_key: hidden_prompt.placeholder,
|
||||
static_prompt.field_key: static_prompt.placeholder,
|
||||
radio_button_group.field_key: radio_button_group.placeholder,
|
||||
hidden_prompt.field_key: hidden_prompt.initial_value,
|
||||
static_prompt.field_key: static_prompt.initial_value,
|
||||
radio_button_group.field_key: radio_button_group.initial_value,
|
||||
dropdown.field_key: "",
|
||||
}
|
||||
|
||||
@ -335,106 +346,176 @@ class TestPromptStage(FlowTestCase):
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
context["text_prompt_expression"] = generate_id()
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")),
|
||||
context["text_prompt_expression"],
|
||||
|
||||
def test_prompt_placeholder_does_not_take_value_from_context(self):
|
||||
"""Test placeholder does not automatically take value from context"""
|
||||
context = {
|
||||
"foo": generate_id(),
|
||||
}
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="text_prompt_expression",
|
||||
label="TEXT_LABEL",
|
||||
type=FieldTypes.TEXT,
|
||||
placeholder="return prompt_context['foo']",
|
||||
placeholder_expression=True,
|
||||
)
|
||||
self.assertNotEqual(
|
||||
context["text_prompt_expression"] = generate_id()
|
||||
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
|
||||
def test_choice_prompts_placeholders(self):
|
||||
"""Test placeholders and expression of choice fields"""
|
||||
context = {"foo": generate_id()}
|
||||
def test_prompt_initial_value(self):
|
||||
"""Test initial_value and expression"""
|
||||
context = {
|
||||
"foo": generate_id(),
|
||||
}
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="text_prompt_expression",
|
||||
label="TEXT_LABEL",
|
||||
type=FieldTypes.TEXT,
|
||||
initial_value="return prompt_context['foo']",
|
||||
initial_value_expression=True,
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
context["text_prompt_expression"] = generate_id()
|
||||
self.assertEqual(
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")),
|
||||
context["text_prompt_expression"],
|
||||
)
|
||||
self.assertNotEqual(
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
|
||||
def test_choice_prompts_placeholder_and_initial_value_no_choices(self):
|
||||
"""Test placeholder and initial value of choice fields with 0 choices"""
|
||||
context = {}
|
||||
|
||||
# No choices - unusable (in the sense it creates an unsubmittable form)
|
||||
# but valid behaviour
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.RADIO_BUTTON_GROUP,
|
||||
placeholder="return []",
|
||||
placeholder_expression=True,
|
||||
initial_value="Invalid choice",
|
||||
initial_value_expression=False,
|
||||
)
|
||||
self.assertEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(prompt.get_initial_value(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(prompt.get_choices(context, self.user, self.factory.get("/")), tuple())
|
||||
context["fixed_choice_prompt_expression"] = generate_id()
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")),
|
||||
context["fixed_choice_prompt_expression"],
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")),
|
||||
(context["fixed_choice_prompt_expression"],),
|
||||
)
|
||||
self.assertNotEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertNotEqual(prompt.get_choices(context, self.user, self.factory.get("/")), tuple())
|
||||
|
||||
del context["fixed_choice_prompt_expression"]
|
||||
def test_choice_prompts_placeholder_and_initial_value_single_choice(self):
|
||||
"""Test placeholder and initial value of choice fields with 1 choice"""
|
||||
context = {"foo": generate_id()}
|
||||
|
||||
# Single choice
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.RADIO_BUTTON_GROUP,
|
||||
placeholder="return prompt_context['foo']",
|
||||
placeholder_expression=True,
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), (context["foo"],)
|
||||
)
|
||||
context["fixed_choice_prompt_expression"] = generate_id()
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")),
|
||||
context["fixed_choice_prompt_expression"],
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")),
|
||||
(context["fixed_choice_prompt_expression"],),
|
||||
)
|
||||
self.assertNotEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
self.assertNotEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), (context["foo"],)
|
||||
)
|
||||
|
||||
del context["fixed_choice_prompt_expression"]
|
||||
|
||||
# Multi choice
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.DROPDOWN,
|
||||
placeholder="return [prompt_context['foo'], True, 'text']",
|
||||
placeholder=context["foo"],
|
||||
placeholder_expression=False,
|
||||
initial_value=context["foo"],
|
||||
initial_value_expression=False,
|
||||
)
|
||||
self.assertEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), (context["foo"],)
|
||||
)
|
||||
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.DROPDOWN,
|
||||
placeholder="return [prompt_context['foo']]",
|
||||
placeholder_expression=True,
|
||||
initial_value="return prompt_context['foo']",
|
||||
initial_value_expression=True,
|
||||
)
|
||||
self.assertEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), (context["foo"],)
|
||||
)
|
||||
|
||||
def test_choice_prompts_placeholder_and_initial_value_multiple_choices(self):
|
||||
"""Test placeholder and initial value of choice fields with multiple choices"""
|
||||
context = {}
|
||||
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.RADIO_BUTTON_GROUP,
|
||||
placeholder="return ['test', True, 42]",
|
||||
placeholder_expression=True,
|
||||
)
|
||||
self.assertEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")), context["foo"]
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")), "test"
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), ("test", True, 42)
|
||||
)
|
||||
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.RADIO_BUTTON_GROUP,
|
||||
placeholder="return ['test', True, 42]",
|
||||
placeholder_expression=True,
|
||||
initial_value="return True",
|
||||
initial_value_expression=True,
|
||||
)
|
||||
self.assertEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(prompt.get_initial_value(context, self.user, self.factory.get("/")), True)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), ("test", True, 42)
|
||||
)
|
||||
|
||||
def test_choice_prompts_placeholder_and_initial_value_from_context(self):
|
||||
"""Test placeholder and initial value of choice fields with values from context"""
|
||||
rand_value = generate_id()
|
||||
context = {
|
||||
"fixed_choice_prompt_expression": rand_value,
|
||||
"fixed_choice_prompt_expression__choices": ["test", 42, rand_value],
|
||||
}
|
||||
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="fixed_choice_prompt_expression",
|
||||
label="LABEL",
|
||||
type=FieldTypes.RADIO_BUTTON_GROUP,
|
||||
)
|
||||
self.assertEqual(prompt.get_placeholder(context, self.user, self.factory.get("/")), "")
|
||||
self.assertEqual(
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")), rand_value
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")), ("test", 42, rand_value)
|
||||
)
|
||||
|
||||
def test_initial_value_not_valid_choice(self):
|
||||
"""Test initial_value not a valid choice"""
|
||||
context = {}
|
||||
prompt: Prompt = Prompt(
|
||||
field_key="choice_prompt",
|
||||
label="TEXT_LABEL",
|
||||
type=FieldTypes.DROPDOWN,
|
||||
placeholder="choice",
|
||||
initial_value="another_choice",
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")),
|
||||
(context["foo"], True, "text"),
|
||||
)
|
||||
context["fixed_choice_prompt_expression"] = tuple(["text", generate_id(), 2])
|
||||
self.assertEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")),
|
||||
"text",
|
||||
("choice",),
|
||||
)
|
||||
self.assertEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")),
|
||||
context["fixed_choice_prompt_expression"],
|
||||
)
|
||||
self.assertNotEqual(
|
||||
prompt.get_placeholder(context, self.user, self.factory.get("/")), context["foo"]
|
||||
)
|
||||
self.assertNotEqual(
|
||||
prompt.get_choices(context, self.user, self.factory.get("/")),
|
||||
(context["foo"], True, "text"),
|
||||
prompt.get_initial_value(context, self.user, self.factory.get("/")),
|
||||
"choice",
|
||||
)
|
||||
|
||||
def test_choices_are_none_for_non_choice_fields(self):
|
||||
@ -505,6 +586,8 @@ class TestPromptStage(FlowTestCase):
|
||||
"type": FieldTypes.TEXT,
|
||||
"placeholder": 'return "Hello world"',
|
||||
"placeholder_expression": True,
|
||||
"initial_value": 'return "Hello Hello world"',
|
||||
"initial_value_expression": True,
|
||||
"sub_text": "test",
|
||||
"order": 123,
|
||||
},
|
||||
@ -522,6 +605,7 @@ class TestPromptStage(FlowTestCase):
|
||||
"type": "text",
|
||||
"required": True,
|
||||
"placeholder": "Hello world",
|
||||
"initial_value": "Hello Hello world",
|
||||
"order": 123,
|
||||
"sub_text": "test",
|
||||
"choices": None,
|
||||
|
@ -3,9 +3,7 @@
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
import authentik.lib.utils.time
|
||||
|
||||
|
@ -13,12 +13,14 @@ entries:
|
||||
id: flow
|
||||
- attrs:
|
||||
order: 200
|
||||
placeholder: |
|
||||
placeholder: Username
|
||||
placeholder_expression: false
|
||||
initial_value: |
|
||||
try:
|
||||
return user.username
|
||||
except:
|
||||
return ''
|
||||
placeholder_expression: true
|
||||
initial_value_expression: true
|
||||
required: true
|
||||
type: text
|
||||
field_key: username
|
||||
@ -29,12 +31,14 @@ entries:
|
||||
model: authentik_stages_prompt.prompt
|
||||
- attrs:
|
||||
order: 201
|
||||
placeholder: |
|
||||
placeholder: Name
|
||||
placeholder_expression: false
|
||||
initial_value: |
|
||||
try:
|
||||
return user.name
|
||||
except:
|
||||
return ''
|
||||
placeholder_expression: true
|
||||
initial_value_expression: true
|
||||
required: true
|
||||
type: text
|
||||
field_key: name
|
||||
@ -45,12 +49,14 @@ entries:
|
||||
model: authentik_stages_prompt.prompt
|
||||
- attrs:
|
||||
order: 202
|
||||
placeholder: |
|
||||
placeholder: Email
|
||||
placeholder_expression: false
|
||||
initial_value: |
|
||||
try:
|
||||
return user.email
|
||||
except:
|
||||
return ''
|
||||
placeholder_expression: true
|
||||
initial_value_expression: true
|
||||
required: true
|
||||
type: email
|
||||
field_key: email
|
||||
@ -61,12 +67,14 @@ entries:
|
||||
model: authentik_stages_prompt.prompt
|
||||
- attrs:
|
||||
order: 203
|
||||
placeholder: |
|
||||
placeholder: Locale
|
||||
placeholder_expression: false
|
||||
initial_value: |
|
||||
try:
|
||||
return user.attributes.get("settings", {}).get("locale", "")
|
||||
except:
|
||||
return ''
|
||||
placeholder_expression: true
|
||||
initial_value_expression: true
|
||||
required: true
|
||||
type: ak-locale
|
||||
field_key: attributes.settings.locale
|
||||
|
109
cmd/ldap/main.go
109
cmd/ldap/main.go
@ -6,11 +6,13 @@ import (
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"goauthentik.io/internal/common"
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/debug"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/ak/healthcheck"
|
||||
"goauthentik.io/internal/outpost/ldap"
|
||||
)
|
||||
|
||||
@ -21,59 +23,72 @@ Required environment variables:
|
||||
- AUTHENTIK_TOKEN: Token to authenticate with
|
||||
- AUTHENTIK_INSECURE: Skip SSL Certificate verification`
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
debug.EnableDebugServer()
|
||||
akURL := config.Get().AuthentikHost
|
||||
if akURL == "" {
|
||||
fmt.Println("env AUTHENTIK_HOST not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akToken := config.Get().AuthentikToken
|
||||
if akToken == "" {
|
||||
fmt.Println("env AUTHENTIK_TOKEN not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
var rootCmd = &cobra.Command{
|
||||
Long: helpMessage,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
debug.EnableDebugServer()
|
||||
akURL := config.Get().AuthentikHost
|
||||
if akURL == "" {
|
||||
fmt.Println("env AUTHENTIK_HOST not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akToken := config.Get().AuthentikToken
|
||||
if akToken == "" {
|
||||
fmt.Println("env AUTHENTIK_TOKEN not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
akURLActual, err := url.Parse(akURL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akURLActual, err := url.Parse(akURL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
go func() {
|
||||
for {
|
||||
<-ex
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
|
||||
ac := ak.NewAPIController(*akURLActual, akToken)
|
||||
if ac == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer ac.Shutdown()
|
||||
|
||||
ac.Server = ldap.NewServer(ac)
|
||||
|
||||
err = ac.Start()
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to run server")
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
go func() {
|
||||
for {
|
||||
<-ex
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
},
|
||||
}
|
||||
|
||||
ac := ak.NewAPIController(*akURLActual, akToken)
|
||||
if ac == nil {
|
||||
func main() {
|
||||
rootCmd.AddCommand(healthcheck.Command)
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer ac.Shutdown()
|
||||
|
||||
ac.Server = ldap.NewServer(ac)
|
||||
|
||||
err = ac.Start()
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to run server")
|
||||
}
|
||||
|
||||
for {
|
||||
<-ex
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,13 @@ import (
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"goauthentik.io/internal/common"
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/debug"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/ak/healthcheck"
|
||||
"goauthentik.io/internal/outpost/proxyv2"
|
||||
)
|
||||
|
||||
@ -24,59 +26,72 @@ Required environment variables:
|
||||
Optionally, you can set these:
|
||||
- AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST`
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
debug.EnableDebugServer()
|
||||
akURL := config.Get().AuthentikHost
|
||||
if akURL == "" {
|
||||
fmt.Println("env AUTHENTIK_HOST not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akToken := config.Get().AuthentikToken
|
||||
if akToken == "" {
|
||||
fmt.Println("env AUTHENTIK_TOKEN not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
var rootCmd = &cobra.Command{
|
||||
Long: helpMessage,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
debug.EnableDebugServer()
|
||||
akURL := config.Get().AuthentikHost
|
||||
if akURL == "" {
|
||||
fmt.Println("env AUTHENTIK_HOST not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akToken := config.Get().AuthentikToken
|
||||
if akToken == "" {
|
||||
fmt.Println("env AUTHENTIK_TOKEN not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
akURLActual, err := url.Parse(akURL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akURLActual, err := url.Parse(akURL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
go func() {
|
||||
for {
|
||||
<-ex
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
|
||||
ac := ak.NewAPIController(*akURLActual, akToken)
|
||||
if ac == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer ac.Shutdown()
|
||||
|
||||
ac.Server = proxyv2.NewProxyServer(ac)
|
||||
|
||||
err = ac.Start()
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to run server")
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
go func() {
|
||||
for {
|
||||
<-ex
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
},
|
||||
}
|
||||
|
||||
ac := ak.NewAPIController(*akURLActual, akToken)
|
||||
if ac == nil {
|
||||
func main() {
|
||||
rootCmd.AddCommand(healthcheck.Command)
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer ac.Shutdown()
|
||||
|
||||
ac.Server = proxyv2.NewProxyServer(ac)
|
||||
|
||||
err = ac.Start()
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to run server")
|
||||
}
|
||||
|
||||
for {
|
||||
<-ex
|
||||
}
|
||||
}
|
||||
|
94
cmd/radius/main.go
Normal file
94
cmd/radius/main.go
Normal file
@ -0,0 +1,94 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"goauthentik.io/internal/common"
|
||||
"goauthentik.io/internal/debug"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/ak/healthcheck"
|
||||
"goauthentik.io/internal/outpost/radius"
|
||||
)
|
||||
|
||||
const helpMessage = `authentik radius
|
||||
|
||||
Required environment variables:
|
||||
- AUTHENTIK_HOST: URL to connect to (format "http://authentik.company")
|
||||
- AUTHENTIK_TOKEN: Token to authenticate with
|
||||
- AUTHENTIK_INSECURE: Skip SSL Certificate verification`
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Long: helpMessage,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
debug.EnableDebugServer()
|
||||
akURL, found := os.LookupEnv("AUTHENTIK_HOST")
|
||||
if !found {
|
||||
fmt.Println("env AUTHENTIK_HOST not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
|
||||
if !found {
|
||||
fmt.Println("env AUTHENTIK_TOKEN not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
akURLActual, err := url.Parse(akURL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
go func() {
|
||||
for {
|
||||
<-ex
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
|
||||
ac := ak.NewAPIController(*akURLActual, akToken)
|
||||
if ac == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer ac.Shutdown()
|
||||
|
||||
ac.Server = radius.NewServer(ac)
|
||||
|
||||
err = ac.Start()
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to run server")
|
||||
}
|
||||
|
||||
for {
|
||||
<-ex
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
rootCmd.AddCommand(healthcheck.Command)
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"goauthentik.io/internal/common"
|
||||
"goauthentik.io/internal/debug"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/radius"
|
||||
)
|
||||
|
||||
const helpMessage = `authentik radius
|
||||
|
||||
Required environment variables:
|
||||
- AUTHENTIK_HOST: URL to connect to (format "http://authentik.company")
|
||||
- AUTHENTIK_TOKEN: Token to authenticate with
|
||||
- AUTHENTIK_INSECURE: Skip SSL Certificate verification`
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
go debug.EnableDebugServer()
|
||||
akURL, found := os.LookupEnv("AUTHENTIK_HOST")
|
||||
if !found {
|
||||
fmt.Println("env AUTHENTIK_HOST not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
akToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
|
||||
if !found {
|
||||
fmt.Println("env AUTHENTIK_TOKEN not set!")
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
akURLActual, err := url.Parse(akURL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(helpMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
go func() {
|
||||
for {
|
||||
<-ex
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
|
||||
ac := ak.NewAPIController(*akURLActual, akToken)
|
||||
if ac == nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer ac.Shutdown()
|
||||
|
||||
ac.Server = radius.NewServer(ac)
|
||||
|
||||
err = ac.Start()
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to run server")
|
||||
}
|
||||
|
||||
for {
|
||||
<-ex
|
||||
}
|
||||
}
|
76
cmd/server/healthcheck.go
Normal file
76
cmd/server/healthcheck.go
Normal file
@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/utils/web"
|
||||
)
|
||||
|
||||
var workerHeartbeat = path.Join(os.TempDir(), "authentik-worker")
|
||||
|
||||
const workerThreshold = 30
|
||||
|
||||
var healthcheckCmd = &cobra.Command{
|
||||
Use: "healthcheck",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) < 1 {
|
||||
os.Exit(1)
|
||||
}
|
||||
mode := args[0]
|
||||
exitCode := 1
|
||||
log.WithField("mode", mode).Debug("checking health")
|
||||
switch strings.ToLower(mode) {
|
||||
case "server":
|
||||
exitCode = checkServer()
|
||||
case "worker":
|
||||
exitCode = checkWorker()
|
||||
default:
|
||||
log.Warn("Invalid mode")
|
||||
}
|
||||
os.Exit(exitCode)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(healthcheckCmd)
|
||||
}
|
||||
|
||||
func checkServer() int {
|
||||
h := &http.Client{
|
||||
Transport: web.NewUserAgentTransport("goauthentik.io/healthcheck", http.DefaultTransport),
|
||||
}
|
||||
url := fmt.Sprintf("http://%s/-/health/ready/", config.Get().Listen.HTTP)
|
||||
res, err := h.Head(url)
|
||||
if err != nil {
|
||||
log.WithError(err).Warning("failed to send healthcheck request")
|
||||
return 1
|
||||
}
|
||||
if res.StatusCode >= 400 {
|
||||
log.WithField("status", res.StatusCode).Warning("unhealthy status code")
|
||||
return 1
|
||||
}
|
||||
log.Debug("successfully checked health")
|
||||
return 0
|
||||
}
|
||||
|
||||
func checkWorker() int {
|
||||
stat, err := os.Stat(workerHeartbeat)
|
||||
if err != nil {
|
||||
log.WithError(err).Warning("failed to check worker heartbeat file")
|
||||
return 1
|
||||
}
|
||||
delta := time.Since(stat.ModTime()).Seconds()
|
||||
if delta > workerThreshold {
|
||||
log.WithField("threshold", workerThreshold).WithField("delta", delta).Warning("Worker hasn't updated heartbeat in threshold")
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
@ -1,132 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/common"
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/constants"
|
||||
"goauthentik.io/internal/debug"
|
||||
"goauthentik.io/internal/gounicorn"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/proxyv2"
|
||||
sentryutils "goauthentik.io/internal/utils/sentry"
|
||||
webutils "goauthentik.io/internal/utils/web"
|
||||
"goauthentik.io/internal/web"
|
||||
"goauthentik.io/internal/web/tenant_tls"
|
||||
)
|
||||
|
||||
var running = true
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
debug.EnableDebugServer()
|
||||
l := log.WithField("logger", "authentik.root")
|
||||
|
||||
if config.Get().ErrorReporting.Enabled {
|
||||
err := sentry.Init(sentry.ClientOptions{
|
||||
Dsn: config.Get().ErrorReporting.SentryDSN,
|
||||
AttachStacktrace: true,
|
||||
EnableTracing: true,
|
||||
TracesSampler: sentryutils.SamplerFunc(config.Get().ErrorReporting.SampleRate),
|
||||
Release: fmt.Sprintf("authentik@%s", constants.VERSION),
|
||||
Environment: config.Get().ErrorReporting.Environment,
|
||||
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgent(), http.DefaultTransport),
|
||||
IgnoreErrors: []string{
|
||||
http.ErrAbortHandler.Error(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
l.WithError(err).Warning("failed to init sentry")
|
||||
}
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
|
||||
u, _ := url.Parse("http://localhost:8000")
|
||||
|
||||
g := gounicorn.New()
|
||||
defer func() {
|
||||
l.Info("shutting down gunicorn")
|
||||
g.Kill()
|
||||
}()
|
||||
ws := web.NewWebServer(g)
|
||||
g.HealthyCallback = func() {
|
||||
if !config.Get().Outposts.DisableEmbeddedOutpost {
|
||||
go attemptProxyStart(ws, u)
|
||||
}
|
||||
}
|
||||
go web.RunMetricsServer()
|
||||
go attemptStartBackend(g)
|
||||
ws.Start()
|
||||
<-ex
|
||||
running = false
|
||||
l.Info("shutting down webserver")
|
||||
go ws.Shutdown()
|
||||
}
|
||||
|
||||
func attemptStartBackend(g *gounicorn.GoUnicorn) {
|
||||
for {
|
||||
if !running {
|
||||
return
|
||||
}
|
||||
err := g.Start()
|
||||
log.WithField("logger", "authentik.router").WithError(err).Warning("gunicorn process died, restarting")
|
||||
}
|
||||
}
|
||||
|
||||
func attemptProxyStart(ws *web.WebServer, u *url.URL) {
|
||||
maxTries := 100
|
||||
attempt := 0
|
||||
l := log.WithField("logger", "authentik.server")
|
||||
for {
|
||||
l.Debug("attempting to init outpost")
|
||||
ac := ak.NewAPIController(*u, config.Get().SecretKey)
|
||||
if ac == nil {
|
||||
attempt += 1
|
||||
time.Sleep(1 * time.Second)
|
||||
if attempt > maxTries {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Init tenant_tls here too since it requires an API Client,
|
||||
// so we just re-use the same one as the outpost uses
|
||||
tw := tenant_tls.NewWatcher(ac.Client)
|
||||
go tw.Start()
|
||||
ws.TenantTLS = tw
|
||||
ac.AddRefreshHandler(func() {
|
||||
tw.Check()
|
||||
})
|
||||
|
||||
srv := proxyv2.NewProxyServer(ac)
|
||||
ws.ProxyServer = srv
|
||||
ac.Server = srv
|
||||
l.Debug("attempting to start outpost")
|
||||
err := ac.StartBackgroundTasks()
|
||||
if err != nil {
|
||||
l.WithError(err).Warning("outpost failed to start")
|
||||
attempt += 1
|
||||
time.Sleep(15 * time.Second)
|
||||
if attempt > maxTries {
|
||||
break
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
select {}
|
||||
}
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
141
cmd/server/server.go
Normal file
141
cmd/server/server.go
Normal file
@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"goauthentik.io/internal/common"
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/constants"
|
||||
"goauthentik.io/internal/debug"
|
||||
"goauthentik.io/internal/gounicorn"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/proxyv2"
|
||||
sentryutils "goauthentik.io/internal/utils/sentry"
|
||||
webutils "goauthentik.io/internal/utils/web"
|
||||
"goauthentik.io/internal/web"
|
||||
"goauthentik.io/internal/web/tenant_tls"
|
||||
)
|
||||
|
||||
var running = true
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "authentik",
|
||||
Short: "Start authentik instance",
|
||||
Version: constants.FullVersion(),
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.JSONFormatter{
|
||||
FieldMap: log.FieldMap{
|
||||
log.FieldKeyMsg: "event",
|
||||
log.FieldKeyTime: "timestamp",
|
||||
},
|
||||
DisableHTMLEscape: true,
|
||||
})
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
debug.EnableDebugServer()
|
||||
l := log.WithField("logger", "authentik.root")
|
||||
|
||||
if config.Get().ErrorReporting.Enabled {
|
||||
err := sentry.Init(sentry.ClientOptions{
|
||||
Dsn: config.Get().ErrorReporting.SentryDSN,
|
||||
AttachStacktrace: true,
|
||||
EnableTracing: true,
|
||||
TracesSampler: sentryutils.SamplerFunc(config.Get().ErrorReporting.SampleRate),
|
||||
Release: fmt.Sprintf("authentik@%s", constants.VERSION),
|
||||
Environment: config.Get().ErrorReporting.Environment,
|
||||
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgent(), http.DefaultTransport),
|
||||
IgnoreErrors: []string{
|
||||
http.ErrAbortHandler.Error(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
l.WithError(err).Warning("failed to init sentry")
|
||||
}
|
||||
}
|
||||
|
||||
ex := common.Init()
|
||||
defer common.Defer()
|
||||
|
||||
u, _ := url.Parse("http://localhost:8000")
|
||||
|
||||
g := gounicorn.New()
|
||||
defer func() {
|
||||
l.Info("shutting down gunicorn")
|
||||
g.Kill()
|
||||
}()
|
||||
ws := web.NewWebServer(g)
|
||||
g.HealthyCallback = func() {
|
||||
if !config.Get().Outposts.DisableEmbeddedOutpost {
|
||||
go attemptProxyStart(ws, u)
|
||||
}
|
||||
}
|
||||
go web.RunMetricsServer()
|
||||
go attemptStartBackend(g)
|
||||
ws.Start()
|
||||
<-ex
|
||||
running = false
|
||||
l.Info("shutting down webserver")
|
||||
go ws.Shutdown()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func attemptStartBackend(g *gounicorn.GoUnicorn) {
|
||||
for {
|
||||
if !running {
|
||||
return
|
||||
}
|
||||
err := g.Start()
|
||||
log.WithField("logger", "authentik.router").WithError(err).Warning("gunicorn process died, restarting")
|
||||
}
|
||||
}
|
||||
|
||||
func attemptProxyStart(ws *web.WebServer, u *url.URL) {
|
||||
maxTries := 100
|
||||
attempt := 0
|
||||
l := log.WithField("logger", "authentik.server")
|
||||
for {
|
||||
l.Debug("attempting to init outpost")
|
||||
ac := ak.NewAPIController(*u, config.Get().SecretKey)
|
||||
if ac == nil {
|
||||
attempt += 1
|
||||
time.Sleep(1 * time.Second)
|
||||
if attempt > maxTries {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Init tenant_tls here too since it requires an API Client,
|
||||
// so we just re-use the same one as the outpost uses
|
||||
tw := tenant_tls.NewWatcher(ac.Client)
|
||||
go tw.Start()
|
||||
ws.TenantTLS = tw
|
||||
ac.AddRefreshHandler(func() {
|
||||
tw.Check()
|
||||
})
|
||||
|
||||
srv := proxyv2.NewProxyServer(ac)
|
||||
ws.ProxyServer = srv
|
||||
ac.Server = srv
|
||||
l.Debug("attempting to start outpost")
|
||||
err := ac.StartBackgroundTasks()
|
||||
if err != nil {
|
||||
l.WithError(err).Warning("outpost failed to start")
|
||||
attempt += 1
|
||||
time.Sleep(15 * time.Second)
|
||||
if attempt > maxTries {
|
||||
break
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
select {}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
version: '3.4'
|
||||
version: "3.4"
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
@ -14,9 +14,9 @@ services:
|
||||
volumes:
|
||||
- database:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=${PG_PASS:?database password required}
|
||||
- POSTGRES_USER=${PG_USER:-authentik}
|
||||
- POSTGRES_DB=${PG_DB:-authentik}
|
||||
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
|
||||
POSTGRES_USER: ${PG_USER:-authentik}
|
||||
POSTGRES_DB: ${PG_DB:-authentik}
|
||||
env_file:
|
||||
- .env
|
||||
redis:
|
||||
@ -32,7 +32,7 @@ services:
|
||||
volumes:
|
||||
- redis:/data
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.4.0}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.4.1}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -47,10 +47,10 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "${AUTHENTIK_PORT_HTTP:-9000}:9000"
|
||||
- "${AUTHENTIK_PORT_HTTPS:-9443}:9443"
|
||||
- "${COMPOSE_PORT_HTTP:-9000}:9000"
|
||||
- "${COMPOSE_PORT_HTTPS:-9443}:9443"
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.4.0}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.4.1}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
25
go.mod
25
go.mod
@ -9,7 +9,7 @@ require (
|
||||
github.com/getsentry/sentry-go v0.20.0
|
||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/go-openapi/runtime v0.25.0
|
||||
github.com/go-openapi/runtime v0.26.0
|
||||
github.com/go-openapi/strfmt v0.21.7
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
@ -24,8 +24,9 @@ require (
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/prometheus/client_golang v1.15.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
goauthentik.io/api/v3 v3.2023040.1
|
||||
goauthentik.io/api/v3 v3.2023041.3
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.7.0
|
||||
golang.org/x/sync v0.1.0
|
||||
@ -36,8 +37,6 @@ require (
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
@ -48,15 +47,16 @@ require (
|
||||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||
github.com/go-openapi/errors v0.20.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/validate v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/loads v0.21.2 // indirect
|
||||
github.com/go-openapi/spec v0.20.8 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-openapi/validate v0.22.1 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
@ -69,9 +69,10 @@ require (
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
go.mongodb.org/mongo-driver v1.11.3 // indirect
|
||||
go.opentelemetry.io/otel v1.11.1 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.11.1 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/net v0.9.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
|
51
go.sum
51
go.sum
@ -38,9 +38,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb h1:w9IDEB7P1VzNcBpOG7kMpFkZp2DkyJIUt0gDx5MBhRU=
|
||||
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb/go.mod h1:9XMFaCeRyW7fC9XJOWQ+NdAv8VLG7ys7l3x4ozEGLUQ=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
@ -57,6 +55,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@ -90,33 +89,41 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU=
|
||||
github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
|
||||
github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc=
|
||||
github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
|
||||
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc=
|
||||
github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||
github.com/go-openapi/loads v0.21.1 h1:Wb3nVZpdEzDTcly8S4HMkey6fjARRzb7iEaySimlDW0=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
|
||||
github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc=
|
||||
github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs=
|
||||
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
|
||||
github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro=
|
||||
github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
|
||||
github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc=
|
||||
github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ=
|
||||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
||||
github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU=
|
||||
github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
||||
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
|
||||
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
||||
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
|
||||
github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k=
|
||||
github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI=
|
||||
github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
|
||||
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||
@ -215,6 +222,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1 h1:cHgCSMS7TdQcoprXnWUptJZzyFsqs18Lt8VVhRuZYVU=
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
@ -283,13 +292,18 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@ -318,6 +332,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
|
||||
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
|
||||
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
|
||||
go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y=
|
||||
go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@ -325,14 +340,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4=
|
||||
go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE=
|
||||
go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs=
|
||||
go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=
|
||||
go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=
|
||||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
|
||||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
|
||||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
|
||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
goauthentik.io/api/v3 v3.2023040.1 h1:WuMkilnvamibI3wMrOdNbMz4q3jbTheq0u3K97ZwYGM=
|
||||
goauthentik.io/api/v3 v3.2023040.1/go.mod h1:A2I2iDSEu0pW13mAT6J6wMWVSeV5+F52MWlcIHmERvk=
|
||||
goauthentik.io/api/v3 v3.2023041.3 h1:2NkeBK1LywjcWYGLZjw9gmscTyOfAeRjUWfBZfq9aeU=
|
||||
goauthentik.io/api/v3 v3.2023041.3/go.mod h1:A2I2iDSEu0pW13mAT6J6wMWVSeV5+F52MWlcIHmERvk=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
|
@ -30,7 +30,7 @@ type RedisConfig struct {
|
||||
Password string `yaml:"password" env:"AUTHENTIK_REDIS__PASSWORD"`
|
||||
TLS bool `yaml:"tls" env:"AUTHENTIK_REDIS__TLS"`
|
||||
TLSReqs string `yaml:"tls_reqs" env:"AUTHENTIK_REDIS__TLS_REQS"`
|
||||
DB int `yaml:"cache_db" env:"AUTHENTIK_REDIS__CACHE_DB"`
|
||||
DB int `yaml:"cache_db" env:"AUTHENTIK_REDIS__DB"`
|
||||
CacheTimeout int `yaml:"cache_timeout" env:"AUTHENTIK_REDIS__CACHE_TIMEOUT"`
|
||||
CacheTimeoutFlows int `yaml:"cache_timeout_flows" env:"AUTHENTIK_REDIS__CACHE_TIMEOUT_FLOWS"`
|
||||
CacheTimeoutPolicies int `yaml:"cache_timeout_policies" env:"AUTHENTIK_REDIS__CACHE_TIMEOUT_POLICIES"`
|
||||
|
@ -29,4 +29,4 @@ func UserAgent() string {
|
||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||
}
|
||||
|
||||
const VERSION = "2023.4.0"
|
||||
const VERSION = "2023.4.1"
|
||||
|
38
internal/outpost/ak/healthcheck/cmd.go
Normal file
38
internal/outpost/ak/healthcheck/cmd.go
Normal file
@ -0,0 +1,38 @@
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"goauthentik.io/internal/config"
|
||||
"goauthentik.io/internal/utils/web"
|
||||
)
|
||||
|
||||
var Command = &cobra.Command{
|
||||
Use: "healthcheck",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
config.Get()
|
||||
os.Exit(check())
|
||||
},
|
||||
}
|
||||
|
||||
func check() int {
|
||||
h := &http.Client{
|
||||
Transport: web.NewUserAgentTransport("goauthentik.io/healthcheck", http.DefaultTransport),
|
||||
}
|
||||
url := fmt.Sprintf("http://%s/outpost.goauthentik.io/ping", config.Get().Listen.Metrics)
|
||||
res, err := h.Head(url)
|
||||
if err != nil {
|
||||
log.WithError(err).Warning("failed to send healthcheck request")
|
||||
return 1
|
||||
}
|
||||
if res.StatusCode >= 400 {
|
||||
log.WithField("status", res.StatusCode).Warning("unhealthy status code")
|
||||
return 1
|
||||
}
|
||||
log.Debug("successfully checked health")
|
||||
return 0
|
||||
}
|
@ -13,33 +13,16 @@ import (
|
||||
|
||||
func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry {
|
||||
dn := pi.GetUserDN(u.Username)
|
||||
userValueMap := func(value []string) []string {
|
||||
attrs := utils.AttributesToLDAP(u.Attributes, func(key string) string {
|
||||
return utils.AttributeKeySanitize(key)
|
||||
}, func(value []string) []string {
|
||||
for i, v := range value {
|
||||
if strings.Contains(v, "%s") {
|
||||
value[i] = fmt.Sprintf(v, u.Username)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
attrs := utils.AttributesToLDAP(u.Attributes, func(key string) string {
|
||||
return utils.AttributeKeySanitize(key)
|
||||
}, userValueMap)
|
||||
rawAttrs := utils.AttributesToLDAP(u.Attributes, func(key string) string {
|
||||
return key
|
||||
}, userValueMap)
|
||||
// Only append attributes that don't already exist
|
||||
// TODO: Remove in 2023.3
|
||||
for _, rawAttr := range rawAttrs {
|
||||
exists := false
|
||||
for _, attr := range attrs {
|
||||
if strings.EqualFold(attr.Name, rawAttr.Name) {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
attrs = append(attrs, rawAttr)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if u.IsActive == nil {
|
||||
u.IsActive = api.PtrBool(false)
|
||||
@ -48,10 +31,6 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry {
|
||||
u.Email = api.PtrString("")
|
||||
}
|
||||
attrs = utils.EnsureAttributes(attrs, map[string][]string{
|
||||
// Old fields for backwards compatibility
|
||||
"goauthentik.io/ldap/active": {strconv.FormatBool(*u.IsActive)},
|
||||
"goauthentik.io/ldap/superuser": {strconv.FormatBool(u.IsSuperuser)},
|
||||
// End old fields
|
||||
"ak-active": {strconv.FormatBool(*u.IsActive)},
|
||||
"ak-superuser": {strconv.FormatBool(u.IsSuperuser)},
|
||||
"memberOf": pi.GroupsForUser(u),
|
||||
|
@ -2,7 +2,6 @@ package group
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/api/v3"
|
||||
@ -28,24 +27,6 @@ func (lg *LDAPGroup) Entry() *ldap.Entry {
|
||||
}, func(value []string) []string {
|
||||
return value
|
||||
})
|
||||
rawAttrs := utils.AttributesToLDAP(lg.Attributes, func(key string) string {
|
||||
return key
|
||||
}, func(value []string) []string {
|
||||
return value
|
||||
})
|
||||
// Only append attributes that don't already exist
|
||||
// TODO: Remove in 2023.3
|
||||
for _, rawAttr := range rawAttrs {
|
||||
exists := false
|
||||
for _, attr := range attrs {
|
||||
if strings.EqualFold(attr.Name, rawAttr.Name) {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
attrs = append(attrs, rawAttr)
|
||||
}
|
||||
}
|
||||
|
||||
objectClass := []string{constants.OCGroup, constants.OCGroupOfUniqueNames, constants.OCGroupOfNames, constants.OCAKGroup, constants.OCPosixGroup}
|
||||
if lg.IsVirtualGroup {
|
||||
@ -53,9 +34,6 @@ func (lg *LDAPGroup) Entry() *ldap.Entry {
|
||||
}
|
||||
|
||||
attrs = utils.EnsureAttributes(attrs, map[string][]string{
|
||||
// Old fields for backwards compatibility
|
||||
"goauthentik.io/ldap/superuser": {strconv.FormatBool(lg.IsSuperuser)},
|
||||
// End old fields
|
||||
"ak-superuser": {strconv.FormatBool(lg.IsSuperuser)},
|
||||
"objectClass": objectClass,
|
||||
"member": lg.Member,
|
||||
|
@ -19,7 +19,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
|
||||
|
||||
COPY --from=builder /go/ldap /
|
||||
|
||||
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "wget", "--spider", "http://localhost:9300/outpost.goauthentik.io/ping" ]
|
||||
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/ldap", "healthcheck" ]
|
||||
|
||||
EXPOSE 3389 6636 9300
|
||||
|
||||
|
28
lifecycle/ak
28
lifecycle/ak
@ -1,6 +1,5 @@
|
||||
#!/bin/bash -e
|
||||
MODE_FILE="${TMPDIR}/authentik-mode"
|
||||
WORKER_HEARTBEAT="${TMPDIR}/authentik-worker"
|
||||
|
||||
function log {
|
||||
printf '{"event": "%s", "level": "info", "logger": "bootstrap"}\n' "$@" > /dev/stderr
|
||||
@ -38,6 +37,14 @@ function check_if_root {
|
||||
exec chpst -u authentik:$GROUP env HOME=/authentik $1
|
||||
}
|
||||
|
||||
function run_authentik {
|
||||
if [[ -x "$(command -v authentik)" ]]; then
|
||||
exec authentik $@
|
||||
else
|
||||
exec go run -v ./cmd/server/ $@
|
||||
fi
|
||||
}
|
||||
|
||||
function set_mode {
|
||||
echo $1 > $MODE_FILE
|
||||
trap cleanup EXIT
|
||||
@ -56,11 +63,7 @@ if [[ "$1" == "server" ]]; then
|
||||
if [[ ! -z "${AUTHENTIK_BOOTSTRAP_PASSWORD}" || ! -z "${AUTHENTIK_BOOTSTRAP_TOKEN}" ]]; then
|
||||
python -m manage bootstrap_tasks
|
||||
fi
|
||||
if [[ -x "$(command -v authentik)" ]]; then
|
||||
exec authentik
|
||||
else
|
||||
exec go run -v ./cmd/server/
|
||||
fi
|
||||
run_authentik
|
||||
elif [[ "$1" == "worker" ]]; then
|
||||
wait_for_db
|
||||
set_mode "worker"
|
||||
@ -77,18 +80,7 @@ elif [[ "$1" == "test-all" ]]; then
|
||||
chown authentik:authentik /unittest.xml
|
||||
check_if_root "python -m manage test authentik"
|
||||
elif [[ "$1" == "healthcheck" ]]; then
|
||||
mode=$(cat $MODE_FILE)
|
||||
if [[ $mode == "server" ]]; then
|
||||
exec curl --user-agent "goauthentik.io lifecycle Healthcheck" -I http://localhost:9000/-/health/ready/
|
||||
elif [[ $mode == "worker" ]]; then
|
||||
mtime=$(date -r $WORKER_HEARTBEAT +"%s")
|
||||
time=$(date +"%s")
|
||||
if [ "$(( $time - $mtime ))" -gt "30" ]; then
|
||||
log "Worker hasn't updated heartbeat in 30 seconds"
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
run_authentik healthcheck $(cat $MODE_FILE)
|
||||
elif [[ "$1" == "dump_config" ]]; then
|
||||
exec python -m authentik.lib.config
|
||||
elif [[ "$1" == "debug" ]]; then
|
||||
|
@ -155,6 +155,6 @@ if not CONFIG.y_bool("disable_startup_analytics", False):
|
||||
},
|
||||
timeout=5,
|
||||
)
|
||||
# pylint: disable=bare-except
|
||||
except: # nosec
|
||||
# pylint: disable=broad-exception-caught
|
||||
except Exception: # nosec
|
||||
pass
|
||||
|
152
poetry.lock
generated
152
poetry.lock
generated
@ -175,6 +175,64 @@ doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
|
||||
test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"]
|
||||
trio = ["trio (>=0.16,<0.22)"]
|
||||
|
||||
[[package]]
|
||||
name = "argon2-cffi"
|
||||
version = "21.3.0"
|
||||
description = "The secure Argon2 password hashing algorithm."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "argon2-cffi-21.3.0.tar.gz", hash = "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b"},
|
||||
{file = "argon2_cffi-21.3.0-py3-none-any.whl", hash = "sha256:8c976986f2c5c0e5000919e6de187906cfd81fb1c72bf9d88c01177e77da7f80"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
argon2-cffi-bindings = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["cogapp", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "pre-commit", "pytest", "sphinx", "sphinx-notfound-page", "tomli"]
|
||||
docs = ["furo", "sphinx", "sphinx-notfound-page"]
|
||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "argon2-cffi-bindings"
|
||||
version = "21.2.0"
|
||||
description = "Low-level CFFI bindings for Argon2"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"},
|
||||
{file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.0.1"
|
||||
|
||||
[package.extras]
|
||||
dev = ["cogapp", "pre-commit", "pytest", "wheel"]
|
||||
tests = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "asgiref"
|
||||
version = "3.5.2"
|
||||
@ -242,20 +300,6 @@ files = [
|
||||
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asyncio"
|
||||
version = "3.4.3"
|
||||
description = "reference implementation of PEP 3156"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "asyncio-3.4.3-cp33-none-win32.whl", hash = "sha256:b62c9157d36187eca799c378e572c969f0da87cd5fc42ca372d92cdb06e7e1de"},
|
||||
{file = "asyncio-3.4.3-cp33-none-win_amd64.whl", hash = "sha256:c46a87b48213d7464f22d9a497b9eef8c1928b68320a2fa94240f969f6fec08c"},
|
||||
{file = "asyncio-3.4.3-py3-none-any.whl", hash = "sha256:c4d18b22701821de07bd6aea8b53d21449ec0ec5680645e5317062ea21817d2d"},
|
||||
{file = "asyncio-3.4.3.tar.gz", hash = "sha256:83360ff8bc97980e4ff25c964c7bd3923d333d177aa4f7fb736b019f26c7cb41"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "22.1.0"
|
||||
@ -1632,14 +1676,14 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "6.4.1"
|
||||
version = "6.6.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.4.1-py3-none-any.whl", hash = "sha256:63ace321e24167d12fbb176b6015f4dbe06868c54a2af4f15849586afb9027fd"},
|
||||
{file = "importlib_metadata-6.4.1.tar.gz", hash = "sha256:eb1a7933041f0f85c94cd130258df3fb0dec060ad8c1c9318892ef4192c47ce1"},
|
||||
{file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"},
|
||||
{file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2780,6 +2824,21 @@ pytest = ">=5.4.0"
|
||||
docs = ["sphinx", "sphinx-rtd-theme"]
|
||||
testing = ["Django", "django-configurations (>=2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-github-actions-annotate-failures"
|
||||
version = "0.1.8"
|
||||
description = "pytest plugin to annotate failed tests with a workflow command for GitHub Actions"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
|
||||
files = [
|
||||
{file = "pytest-github-actions-annotate-failures-0.1.8.tar.gz", hash = "sha256:2d6e6cb5f8d0aae4a27a20cc4e20fabd3199a121c57f44bc48fe28e372e0be23"},
|
||||
{file = "pytest_github_actions_annotate_failures-0.1.8-py2.py3-none-any.whl", hash = "sha256:6a882ff21672fa79deae8d917eb965a6bde2b25191e7632e1adfc23ffac008ab"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=4.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "pytest-randomly"
|
||||
version = "3.12.0"
|
||||
@ -3025,16 +3084,43 @@ files = [
|
||||
[package.dependencies]
|
||||
pyasn1 = ">=0.1.3"
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.262"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.0.262-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:c26c1abd420d041592d05d63aee8c6a18feb24aed4deb6e91129e9f2c7b4914a"},
|
||||
{file = "ruff-0.0.262-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b379e9765afa679316e52288a942df085e590862f8945088936a7bce3116d8f3"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7e0ca6821aafbd2b059df3119fcd5881250721ca8e825789fd2c471f7c59be"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cca35e2aeddff72bb4379a1dabc134e0c0d25ebc754a2cb733a1f8d4dbbb5e0"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15bf5533ce169aebbafa00017987f673e879f60a625d932b464b8cdaf32a4fce"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3909e249d984c4517194005a1c30eaa0c3a6d906c789d9fc0c9c7e007fb3e759"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e2813013a19b3e147e840bdb2e42db5825b53b47364e58e7b467c5fa47ffda2"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d25a94996b2037e566c2a801c8b324c0a826194d5d4d90ad7c1ccb8cf06521fa"},
|
||||
{file = "ruff-0.0.262-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ca04348372efc59f6ee808d903d35e0d352cf2c78e487757cd48b65104b83e"},
|
||||
{file = "ruff-0.0.262-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:24f989363e9bb5d0283490298102a5218682e49ebf300e445d69e24bee03ac83"},
|
||||
{file = "ruff-0.0.262-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3c24e678e43ca4b67e29cc9a7a54eea05f31a5898cbf17bfec47b68f08d32a60"},
|
||||
{file = "ruff-0.0.262-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0baff3c9a22227358ea109c165efe62dbdd0f2b9fd5256567dda8682b444fe23"},
|
||||
{file = "ruff-0.0.262-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:083bac6e238d8b7d5ac3618666ea63b7ac661cf94c5da160070a58e190082831"},
|
||||
{file = "ruff-0.0.262-py3-none-win32.whl", hash = "sha256:15bbfa2d15c137717627e0d56b0e535ae297b734551e34e03fcc25d7642cf43a"},
|
||||
{file = "ruff-0.0.262-py3-none-win_amd64.whl", hash = "sha256:973ac29193f718349cf5746b7d86dfeaf7d40e9651ed97790a9b9327305888b9"},
|
||||
{file = "ruff-0.0.262-py3-none-win_arm64.whl", hash = "sha256:f102904ebe395acd2a181d295b98120acd7a63f732b691672977fc688674f4af"},
|
||||
{file = "ruff-0.0.262.tar.gz", hash = "sha256:faea54231c265f5349975ba6f3d855b71881a01f391b2000c47740390c6d5f68"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "selenium"
|
||||
version = "4.8.3"
|
||||
version = "4.9.0"
|
||||
description = ""
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "selenium-4.8.3-py3-none-any.whl", hash = "sha256:28430ac54a54fa59ad1f5392a1b89b169fe3ab2c2ccd1a9a10b6fe74f36cd6da"},
|
||||
{file = "selenium-4.8.3.tar.gz", hash = "sha256:61cda3a304f82637162bc155cae7bf88fdb04c115fa2cb1c1c2e1358fcd19a9f"},
|
||||
{file = "selenium-4.9.0-py3-none-any.whl", hash = "sha256:4c19e6aac202719373108d53a5a8e9336ba8d2b25822ca32ae6ff37acbabbdbe"},
|
||||
{file = "selenium-4.9.0.tar.gz", hash = "sha256:478fae77cdfaec32adb1e68d59632c8c191f920535282abcaa2d1a3d98655624"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3045,14 +3131,14 @@ urllib3 = {version = ">=1.26,<2.0", extras = ["socks"]}
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "1.19.1"
|
||||
version = "1.20.0"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "sentry-sdk-1.19.1.tar.gz", hash = "sha256:7ae78bd921981a5010ab540d6bdf3b793659a4db8cccf7f16180702d48a80d84"},
|
||||
{file = "sentry_sdk-1.19.1-py2.py3-none-any.whl", hash = "sha256:885a11c69df23e53eb281d003b9ff15a5bdfa43d8a2a53589be52104a1b4582f"},
|
||||
{file = "sentry-sdk-1.20.0.tar.gz", hash = "sha256:a3410381ae769a436c0852cce140a5e5e49f566a07fb7c2ab445af1302f6ad89"},
|
||||
{file = "sentry_sdk-1.20.0-py2.py3-none-any.whl", hash = "sha256:0ad6bbbe78057b8031a07de7aca6d2a83234e51adc4d436eaf8d8c697184db71"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3177,16 +3263,21 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlparse"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
description = "A non-validating SQL parser."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"},
|
||||
{file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"},
|
||||
{file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
|
||||
{file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["build", "flake8"]
|
||||
doc = ["sphinx"]
|
||||
test = ["pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "stevedore"
|
||||
version = "4.1.1"
|
||||
@ -3322,20 +3413,19 @@ wsproto = ">=0.14"
|
||||
|
||||
[[package]]
|
||||
name = "twilio"
|
||||
version = "8.0.0"
|
||||
version = "8.1.0"
|
||||
description = "Twilio API client and TwiML generator"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "twilio-8.0.0-py2.py3-none-any.whl", hash = "sha256:40212f0e03947201e0a8f84e6c2a08acd6e61f31f0c94ec04e6b9abae109113a"},
|
||||
{file = "twilio-8.0.0.tar.gz", hash = "sha256:ee2eaaf24df4361200f18d04e14b9937de2c31f3322dd739491590d8ff7196fc"},
|
||||
{file = "twilio-8.1.0-py2.py3-none-any.whl", hash = "sha256:19be48f21e799b9dd10e2e0a5633962438e04842864e806409f4f2dbe446a868"},
|
||||
{file = "twilio-8.1.0.tar.gz", hash = "sha256:a31863119655cd3643f788099f6ea3fe74eea59ce3f65600f9a4931301311c08"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = ">=3.8.4"
|
||||
aiohttp-retry = ">=2.8.3"
|
||||
asyncio = ">=3.4.3"
|
||||
PyJWT = ">=2.0.0,<3.0.0"
|
||||
pytz = "*"
|
||||
requests = ">=2.0.0"
|
||||
@ -4062,4 +4152,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "61d20a7f2b76b6554b4c2095db152395c41d6c650b2f7f16662d5ed2f8cc0983"
|
||||
content-hash = "82fc267d6041997d1410a951033cdb9f6c57d91df7d48acaecdbab320daab58e"
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Stage 1: Build website
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:18 as web-builder
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/node:20 as web-builder
|
||||
|
||||
COPY ./web /static/
|
||||
|
||||
@ -32,7 +32,7 @@ COPY --from=web-builder /static/security.txt /web/security.txt
|
||||
COPY --from=web-builder /static/dist/ /web/dist/
|
||||
COPY --from=web-builder /static/authentik/ /web/authentik/
|
||||
|
||||
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "wget", "--spider", "http://localhost:9300/outpost.goauthentik.io/ping" ]
|
||||
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/proxy", "healthcheck" ]
|
||||
|
||||
EXPOSE 9000 9300 9443
|
||||
|
||||
|
@ -17,6 +17,11 @@ line-length = 100
|
||||
target-version = ['py311']
|
||||
exclude = 'node_modules'
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
exclude = ["**/migrations/**", "**/node_modules/**"]
|
||||
|
||||
[tool.isort]
|
||||
multi_line_output = 3
|
||||
include_trailing_comma = true
|
||||
@ -30,12 +35,12 @@ force_to_top = "*"
|
||||
source = ["authentik"]
|
||||
relative_files = true
|
||||
omit = [
|
||||
"*/asgi.py",
|
||||
"manage.py",
|
||||
"*/migrations/*",
|
||||
"*/management/commands/*",
|
||||
"*/apps.py",
|
||||
"website/",
|
||||
"*/asgi.py",
|
||||
"manage.py",
|
||||
"*/migrations/*",
|
||||
"*/management/commands/*",
|
||||
"*/apps.py",
|
||||
"website/",
|
||||
]
|
||||
|
||||
[tool.coverage.report]
|
||||
@ -43,19 +48,19 @@ sort = "Cover"
|
||||
skip_covered = true
|
||||
precision = 2
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
# Don't complain about missing debug-only code:
|
||||
"def __unicode__",
|
||||
"def __str__",
|
||||
"def __repr__",
|
||||
"if self.debug",
|
||||
"if TYPE_CHECKING",
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
"raise AssertionError",
|
||||
"raise NotImplementedError",
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
"if 0:",
|
||||
"if __name__ == .__main__.:",
|
||||
"pragma: no cover",
|
||||
# Don't complain about missing debug-only code:
|
||||
"def __unicode__",
|
||||
"def __str__",
|
||||
"def __repr__",
|
||||
"if self.debug",
|
||||
"if TYPE_CHECKING",
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
"raise AssertionError",
|
||||
"raise NotImplementedError",
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
"if 0:",
|
||||
"if __name__ == .__main__.:",
|
||||
]
|
||||
show_missing = true
|
||||
|
||||
@ -64,20 +69,20 @@ good-names = ["pk", "id", "i", "j", "k", "_", "bar"]
|
||||
|
||||
[tool.pylint.master]
|
||||
disable = [
|
||||
"arguments-differ",
|
||||
"locally-disabled",
|
||||
"too-many-ancestors",
|
||||
"too-few-public-methods",
|
||||
"import-outside-toplevel",
|
||||
"signature-differs",
|
||||
"similarities",
|
||||
"cyclic-import",
|
||||
"protected-access",
|
||||
"unused-argument",
|
||||
"raise-missing-from",
|
||||
"fixme",
|
||||
# To preserve django's translation function we need to use %-formatting
|
||||
"consider-using-f-string",
|
||||
"arguments-differ",
|
||||
"locally-disabled",
|
||||
"too-many-ancestors",
|
||||
"too-few-public-methods",
|
||||
"import-outside-toplevel",
|
||||
"signature-differs",
|
||||
"similarities",
|
||||
"cyclic-import",
|
||||
"protected-access",
|
||||
"unused-argument",
|
||||
"raise-missing-from",
|
||||
"fixme",
|
||||
# To preserve django's translation function we need to use %-formatting
|
||||
"consider-using-f-string",
|
||||
]
|
||||
|
||||
load-plugins = ["pylint_django", "pylint.extensions.bad_builtin"]
|
||||
@ -99,17 +104,18 @@ python_files = ["tests.py", "test_*.py", "*_tests.py"]
|
||||
junit_family = "xunit2"
|
||||
addopts = "-p no:celery --junitxml=unittest.xml"
|
||||
filterwarnings = [
|
||||
"ignore:defusedxml.lxml is no longer supported and will be removed in a future release.:DeprecationWarning",
|
||||
"ignore:SelectableGroups dict interface is deprecated. Use select.:DeprecationWarning",
|
||||
"ignore:defusedxml.lxml is no longer supported and will be removed in a future release.:DeprecationWarning",
|
||||
"ignore:SelectableGroups dict interface is deprecated. Use select.:DeprecationWarning",
|
||||
]
|
||||
|
||||
[tool.poetry]
|
||||
name = "authentik"
|
||||
version = "2023.4.0"
|
||||
version = "2023.4.1"
|
||||
description = ""
|
||||
authors = ["authentik Team <hello@goauthentik.io>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
argon2-cffi = "*"
|
||||
celery = "*"
|
||||
channels = { version = "*", extras = ["daphne"] }
|
||||
channels-redis = "*"
|
||||
@ -176,8 +182,10 @@ pylint-django = "*"
|
||||
pyrad = "*"
|
||||
pytest = "*"
|
||||
pytest-django = "*"
|
||||
pytest-github-actions-annotate-failures = "*"
|
||||
pytest-randomly = "*"
|
||||
requests-mock = "*"
|
||||
ruff = "*"
|
||||
selenium = "*"
|
||||
|
||||
[build-system]
|
||||
|
@ -19,7 +19,7 @@ ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
|
||||
|
||||
COPY --from=builder /go/radius /
|
||||
|
||||
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "wget", "--spider", "http://localhost:9300/outpost.goauthentik.io/ping" ]
|
||||
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/radius", "healthcheck" ]
|
||||
|
||||
EXPOSE 1812/udp 9300
|
||||
|
||||
|
48
schema.yml
48
schema.yml
@ -1,7 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: authentik
|
||||
version: 2023.4.0
|
||||
version: 2023.4.1
|
||||
description: Making authentication simple.
|
||||
contact:
|
||||
email: hello@goauthentik.io
|
||||
@ -26351,6 +26351,7 @@ components:
|
||||
- authentik.tenants
|
||||
- authentik.blueprints
|
||||
- authentik.core
|
||||
- authentik.enterprise
|
||||
type: string
|
||||
description: |-
|
||||
* `authentik.admin` - authentik Admin
|
||||
@ -26400,6 +26401,7 @@ components:
|
||||
* `authentik.tenants` - authentik Tenants
|
||||
* `authentik.blueprints` - authentik Blueprints
|
||||
* `authentik.core` - authentik Core
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
AppleChallengeResponseRequest:
|
||||
type: object
|
||||
description: Pseudo class for plex response
|
||||
@ -27708,12 +27710,14 @@ components:
|
||||
- can_geo_ip
|
||||
- can_impersonate
|
||||
- can_debug
|
||||
- is_enterprise
|
||||
type: string
|
||||
description: |-
|
||||
* `can_save_media` - Can Save Media
|
||||
* `can_geo_ip` - Can Geo Ip
|
||||
* `can_impersonate` - Can Impersonate
|
||||
* `can_debug` - Can Debug
|
||||
* `is_enterprise` - Is Enterprise
|
||||
CaptchaChallenge:
|
||||
type: object
|
||||
description: Site public key
|
||||
@ -29114,6 +29118,7 @@ components:
|
||||
* `authentik.tenants` - authentik Tenants
|
||||
* `authentik.blueprints` - authentik Blueprints
|
||||
* `authentik.core` - authentik Core
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
required:
|
||||
- bound_to
|
||||
- component
|
||||
@ -29223,6 +29228,7 @@ components:
|
||||
* `authentik.tenants` - authentik Tenants
|
||||
* `authentik.blueprints` - authentik Blueprints
|
||||
* `authentik.core` - authentik Core
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
required:
|
||||
- name
|
||||
EventRequest:
|
||||
@ -35908,6 +35914,7 @@ components:
|
||||
* `authentik.tenants` - authentik Tenants
|
||||
* `authentik.blueprints` - authentik Blueprints
|
||||
* `authentik.core` - authentik Core
|
||||
* `authentik.enterprise` - authentik Enterprise
|
||||
PatchedEventRequest:
|
||||
type: object
|
||||
description: Event Serializer
|
||||
@ -36862,8 +36869,14 @@ components:
|
||||
type: boolean
|
||||
placeholder:
|
||||
type: string
|
||||
description: When creating a Radio Button Group or Dropdown, enable interpreting
|
||||
as expression and return a list to return multiple choices.
|
||||
description: Optionally provide a short hint that describes the expected
|
||||
input value. When creating a fixed choice field, enable interpreting as
|
||||
expression and return a list to return multiple choices.
|
||||
initial_value:
|
||||
type: string
|
||||
description: Optionally pre-fill the input with an initial value. When creating
|
||||
a fixed choice field, enable interpreting as expression and return a list
|
||||
to return multiple default choices.
|
||||
order:
|
||||
type: integer
|
||||
maximum: 2147483647
|
||||
@ -36876,6 +36889,8 @@ components:
|
||||
type: string
|
||||
placeholder_expression:
|
||||
type: boolean
|
||||
initial_value_expression:
|
||||
type: boolean
|
||||
PatchedPromptStageRequest:
|
||||
type: object
|
||||
description: PromptStage Serializer
|
||||
@ -38034,8 +38049,14 @@ components:
|
||||
type: boolean
|
||||
placeholder:
|
||||
type: string
|
||||
description: When creating a Radio Button Group or Dropdown, enable interpreting
|
||||
as expression and return a list to return multiple choices.
|
||||
description: Optionally provide a short hint that describes the expected
|
||||
input value. When creating a fixed choice field, enable interpreting as
|
||||
expression and return a list to return multiple choices.
|
||||
initial_value:
|
||||
type: string
|
||||
description: Optionally pre-fill the input with an initial value. When creating
|
||||
a fixed choice field, enable interpreting as expression and return a list
|
||||
to return multiple default choices.
|
||||
order:
|
||||
type: integer
|
||||
maximum: 2147483647
|
||||
@ -38048,6 +38069,8 @@ components:
|
||||
type: string
|
||||
placeholder_expression:
|
||||
type: boolean
|
||||
initial_value_expression:
|
||||
type: boolean
|
||||
required:
|
||||
- field_key
|
||||
- label
|
||||
@ -38109,8 +38132,14 @@ components:
|
||||
type: boolean
|
||||
placeholder:
|
||||
type: string
|
||||
description: When creating a Radio Button Group or Dropdown, enable interpreting
|
||||
as expression and return a list to return multiple choices.
|
||||
description: Optionally provide a short hint that describes the expected
|
||||
input value. When creating a fixed choice field, enable interpreting as
|
||||
expression and return a list to return multiple choices.
|
||||
initial_value:
|
||||
type: string
|
||||
description: Optionally pre-fill the input with an initial value. When creating
|
||||
a fixed choice field, enable interpreting as expression and return a list
|
||||
to return multiple default choices.
|
||||
order:
|
||||
type: integer
|
||||
maximum: 2147483647
|
||||
@ -38123,6 +38152,8 @@ components:
|
||||
type: string
|
||||
placeholder_expression:
|
||||
type: boolean
|
||||
initial_value_expression:
|
||||
type: boolean
|
||||
required:
|
||||
- field_key
|
||||
- label
|
||||
@ -40267,6 +40298,8 @@ components:
|
||||
type: boolean
|
||||
placeholder:
|
||||
type: string
|
||||
initial_value:
|
||||
type: string
|
||||
order:
|
||||
type: integer
|
||||
sub_text:
|
||||
@ -40279,6 +40312,7 @@ components:
|
||||
required:
|
||||
- choices
|
||||
- field_key
|
||||
- initial_value
|
||||
- label
|
||||
- order
|
||||
- placeholder
|
||||
|
@ -3,7 +3,7 @@ from yaml import safe_dump
|
||||
|
||||
from authentik.lib.generators import generate_id
|
||||
|
||||
with open("local.env.yml", "w") as _config:
|
||||
with open("local.env.yml", "w", encoding="utf-8") as _config:
|
||||
safe_dump(
|
||||
{
|
||||
"log_level": "debug",
|
||||
|
@ -229,12 +229,6 @@ class TestProviderLDAP(SeleniumTestCase):
|
||||
"homeDirectory": [
|
||||
f"/home/{o_user.username}",
|
||||
],
|
||||
# Old fields for backwards compatibility
|
||||
"goauthentik.io/ldap/active": ["true"],
|
||||
"goauthentik.io/ldap/superuser": ["false"],
|
||||
"goauthentik.io/user/override-ips": ["true"],
|
||||
"goauthentik.io/user/service-account": ["true"],
|
||||
# End old fields
|
||||
"ak-active": ["true"],
|
||||
"ak-superuser": ["false"],
|
||||
"goauthentikio-user-override-ips": ["true"],
|
||||
@ -264,12 +258,6 @@ class TestProviderLDAP(SeleniumTestCase):
|
||||
"homeDirectory": [
|
||||
f"/home/{embedded_account.username}",
|
||||
],
|
||||
# Old fields for backwards compatibility
|
||||
"goauthentik.io/ldap/active": ["true"],
|
||||
"goauthentik.io/ldap/superuser": ["false"],
|
||||
"goauthentik.io/user/override-ips": ["true"],
|
||||
"goauthentik.io/user/service-account": ["true"],
|
||||
# End old fields
|
||||
"ak-active": ["true"],
|
||||
"ak-superuser": ["false"],
|
||||
"goauthentikio-user-override-ips": ["true"],
|
||||
@ -302,10 +290,6 @@ class TestProviderLDAP(SeleniumTestCase):
|
||||
"homeDirectory": [
|
||||
f"/home/{self.user.username}",
|
||||
],
|
||||
# Old fields for backwards compatibility
|
||||
"goauthentik.io/ldap/active": ["true"],
|
||||
"goauthentik.io/ldap/superuser": ["true"],
|
||||
# End old fields
|
||||
"ak-active": ["true"],
|
||||
"ak-superuser": ["true"],
|
||||
"extraAttribute": ["bar"],
|
||||
|
@ -6,7 +6,6 @@ from unittest.case import skipUnless
|
||||
|
||||
from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types import Healthcheck
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as ec
|
||||
|
||||
@ -41,14 +40,9 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
|
||||
sleep(1)
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image="ghcr.io/beryju/oidc-test-client:v1",
|
||||
image="ghcr.io/beryju/oidc-test-client:1.3",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
healthcheck=Healthcheck(
|
||||
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
|
||||
interval=5 * 100 * 1000000,
|
||||
start_period=1 * 100 * 1000000,
|
||||
),
|
||||
environment={
|
||||
"OIDC_CLIENT_ID": self.client_id,
|
||||
"OIDC_CLIENT_SECRET": self.client_secret,
|
||||
|
@ -6,7 +6,6 @@ from unittest.case import skipUnless
|
||||
|
||||
from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types import Healthcheck
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as ec
|
||||
|
||||
@ -41,14 +40,9 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
|
||||
sleep(1)
|
||||
client: DockerClient = from_env()
|
||||
container = client.containers.run(
|
||||
image="ghcr.io/beryju/oidc-test-client:v1",
|
||||
image="ghcr.io/beryju/oidc-test-client:1.3",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
healthcheck=Healthcheck(
|
||||
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
|
||||
interval=5 * 100 * 1000000,
|
||||
start_period=1 * 100 * 1000000,
|
||||
),
|
||||
environment={
|
||||
"OIDC_CLIENT_ID": self.client_id,
|
||||
"OIDC_CLIENT_SECRET": self.client_secret,
|
||||
|
@ -11,7 +11,6 @@ from docker.client import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.blueprints.tests import apply_blueprint, reconcile_app
|
||||
from authentik.core.models import Application
|
||||
from authentik.flows.models import Flow
|
||||
|
@ -6,7 +6,6 @@ from unittest.case import skipUnless
|
||||
|
||||
from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types import Healthcheck
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as ec
|
||||
|
||||
@ -40,14 +39,9 @@ class TestProviderSAML(SeleniumTestCase):
|
||||
if force_post:
|
||||
metadata_url += f"&force_binding={SAML_BINDING_POST}"
|
||||
container = client.containers.run(
|
||||
image="ghcr.io/beryju/saml-test-sp:latest",
|
||||
image="ghcr.io/beryju/saml-test-sp:1.1",
|
||||
detach=True,
|
||||
network_mode="host",
|
||||
healthcheck=Healthcheck(
|
||||
test=["CMD", "wget", "--spider", "http://localhost:9009/health"],
|
||||
interval=5 * 100 * 1000000,
|
||||
start_period=1 * 100 * 1000000,
|
||||
),
|
||||
environment={
|
||||
"SP_ENTITY_ID": provider.issuer,
|
||||
"SP_SSO_BINDING": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
||||
|
@ -3,6 +3,7 @@ import json
|
||||
import os
|
||||
from functools import lru_cache, wraps
|
||||
from os import environ
|
||||
from sys import stderr
|
||||
from time import sleep
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
@ -28,6 +29,7 @@ from authentik.core.models import User
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
|
||||
RETRIES = int(environ.get("RETRIES", "3"))
|
||||
IS_CI = "CI" in environ
|
||||
|
||||
|
||||
def get_docker_tag() -> str:
|
||||
@ -49,6 +51,8 @@ class SeleniumTestCase(StaticLiveServerTestCase):
|
||||
user: User
|
||||
|
||||
def setUp(self):
|
||||
if IS_CI:
|
||||
print("::group::authentik Logs", file=stderr)
|
||||
super().setUp()
|
||||
# pylint: disable=invalid-name
|
||||
self.maxDiff = None
|
||||
@ -91,8 +95,12 @@ class SeleniumTestCase(StaticLiveServerTestCase):
|
||||
def output_container_logs(self, container: Optional[Container] = None):
|
||||
"""Output the container logs to our STDOUT"""
|
||||
_container = container or self.container
|
||||
if IS_CI:
|
||||
print(f"::group::Container logs - {_container.image.tags[0]}")
|
||||
for log in _container.logs().decode().split("\n"):
|
||||
self.logger.info(log, source="container", container=_container.image.tags[0])
|
||||
print(log)
|
||||
if IS_CI:
|
||||
print("::endgroup::")
|
||||
|
||||
def get_container_specs(self) -> Optional[dict[str, Any]]:
|
||||
"""Optionally get container specs which will launched on setup, wait for the container to
|
||||
@ -118,15 +126,19 @@ class SeleniumTestCase(StaticLiveServerTestCase):
|
||||
raise ValueError(f"Webdriver failed after {RETRIES}.")
|
||||
|
||||
def tearDown(self):
|
||||
self.logger.debug("--------browser logs")
|
||||
super().tearDown()
|
||||
if IS_CI:
|
||||
print("::endgroup::", file=stderr)
|
||||
if IS_CI:
|
||||
print("::group::Browser logs")
|
||||
for line in self.driver.get_log("browser"):
|
||||
self.logger.debug(line["message"], source=line["source"], level=line["level"])
|
||||
self.logger.debug("--------end browser logs")
|
||||
print(line["message"])
|
||||
if IS_CI:
|
||||
print("::endgroup::")
|
||||
if self.container:
|
||||
self.output_container_logs()
|
||||
self.container.kill()
|
||||
self.driver.quit()
|
||||
super().tearDown()
|
||||
|
||||
def wait_for_url(self, desired_url):
|
||||
"""Wait until URL is `desired_url`."""
|
||||
|
@ -9,7 +9,6 @@ from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types.healthcheck import Healthcheck
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.core.tests.utils import create_test_flow
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.outposts.controllers.docker import DockerController
|
||||
|
@ -9,7 +9,6 @@ from docker import DockerClient, from_env
|
||||
from docker.models.containers import Container
|
||||
from docker.types.healthcheck import Healthcheck
|
||||
|
||||
from authentik import __version__
|
||||
from authentik.core.tests.utils import create_test_flow
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.outposts.models import (
|
||||
|
255
web/package-lock.json
generated
255
web/package-lock.json
generated
@ -15,14 +15,14 @@
|
||||
"@babel/preset-env": "^7.21.4",
|
||||
"@babel/preset-typescript": "^7.21.4",
|
||||
"@codemirror/lang-html": "^6.4.3",
|
||||
"@codemirror/lang-javascript": "^6.1.6",
|
||||
"@codemirror/lang-javascript": "^6.1.7",
|
||||
"@codemirror/lang-python": "^6.1.2",
|
||||
"@codemirror/lang-xml": "^6.0.2",
|
||||
"@codemirror/legacy-modes": "^6.3.2",
|
||||
"@codemirror/theme-one-dark": "^6.1.1",
|
||||
"@formatjs/intl-listformat": "^7.1.9",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@formatjs/intl-listformat": "^7.2.1",
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@goauthentik/api": "^2023.4.0-1681471246",
|
||||
"@goauthentik/api": "^2023.4.1-1681914191",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||
"@lingui/cli": "^3.17.2",
|
||||
@ -35,15 +35,15 @@
|
||||
"@rollup/plugin-node-resolve": "^15.0.2",
|
||||
"@rollup/plugin-replace": "^5.0.2",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@sentry/browser": "^7.48.0",
|
||||
"@sentry/tracing": "^7.48.0",
|
||||
"@sentry/browser": "^7.49.0",
|
||||
"@sentry/tracing": "^7.49.0",
|
||||
"@squoosh/cli": "^0.7.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||
"@types/chart.js": "^2.9.37",
|
||||
"@types/codemirror": "5.60.7",
|
||||
"@types/grecaptcha": "^3.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
||||
"@typescript-eslint/parser": "^5.58.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
@ -54,16 +54,16 @@
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"core-js": "^3.30.1",
|
||||
"country-flag-icons": "^1.5.7",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.8",
|
||||
"eslint-plugin-lit": "^1.8.2",
|
||||
"eslint-plugin-lit": "^1.8.3",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lit": "^2.7.2",
|
||||
"mermaid": "^10.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"prettier": "^2.8.7",
|
||||
"pyright": "^1.1.303",
|
||||
"prettier": "^2.8.8",
|
||||
"pyright": "^1.1.304",
|
||||
"rapidoc": "^9.3.4",
|
||||
"rollup": "^2.79.1",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
@ -1788,9 +1788,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-javascript": {
|
||||
"version": "6.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.1.6.tgz",
|
||||
"integrity": "sha512-TTK28z+vJQY9GAefLTDDptI2LMqMfAiuTpt8s9SsNwocjVQ1v9yTzfReMf1hYhspQCdhfa7fdKnQJ78mKe/bHQ==",
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.1.7.tgz",
|
||||
"integrity": "sha512-KXKqxlZ4W6t5I7i2ScmITUD3f/F5Cllk3kj0De9P9mFeYVfhOVOWuDLgYiLpk357u7Xh4dhqjJAnsNPPoTLghQ==",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/language": "^6.6.0",
|
||||
@ -1870,9 +1870,9 @@
|
||||
"integrity": "sha512-g+3OJuRylV5qsXuuhrc6Cvs1NQluNioepYMM2fhnpYkNk7NgX+j0AFuevKSVKzTDmDyt9+Puju+zPdHNECzCNQ=="
|
||||
},
|
||||
"node_modules/@codemirror/theme-one-dark": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz",
|
||||
"integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
||||
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
@ -1982,9 +1982,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz",
|
||||
"integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==",
|
||||
"version": "8.39.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz",
|
||||
"integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
@ -1999,9 +1999,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/intl-listformat": {
|
||||
"version": "7.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.1.9.tgz",
|
||||
"integrity": "sha512-5YikxwRqRXTVWVujhswDOTCq6gs+m9IcNbNZLa6FLtyBStAjEsuE2vAU+lPsbz9ZTST57D5fodjIh2JXT6sMWQ==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.2.1.tgz",
|
||||
"integrity": "sha512-fRJFWLrGa7d25I4JSxNjKX29oXGcIXx8fJjgURnvs2C3ijS4gurUgFrUwLbv/2KfPfyJ5g567pz2INelNJZBdw==",
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": "1.14.3",
|
||||
"@formatjs/intl-localematcher": "0.2.32",
|
||||
@ -2026,9 +2026,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@goauthentik/api": {
|
||||
"version": "2023.4.0-1681471246",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.4.0-1681471246.tgz",
|
||||
"integrity": "sha512-/P9CfSHM4qEe1eaphC5MTYb/4yVrXBqME2amrj9JtK8dItGM/qSGDMIS8v18zZUsbO5fM+RQ/AtL/Izj1COZWA=="
|
||||
"version": "2023.4.1-1681914191",
|
||||
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.4.1-1681914191.tgz",
|
||||
"integrity": "sha512-8SOx9DIcghKQdXJgerQehiIX3588Tn6SjwBdsi9OsI0yFdSLfJpIBVuMOmW3vdGpjVThSaMsK91KKRo4VqpcUw=="
|
||||
},
|
||||
"node_modules/@hcaptcha/types": {
|
||||
"version": "1.0.3",
|
||||
@ -2949,13 +2949,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/tracing": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.48.0.tgz",
|
||||
"integrity": "sha512-MFAPDTrvCtfSm0/Zbmx7HA0Q5uCfRadOUpN8Y8rP1ndz+329h2kA3mZRCuC+3/aXL11zs2CHUhcAkGjwH2vogg==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.49.0.tgz",
|
||||
"integrity": "sha512-ESh3+ZneQk/3HESTUmIPNrW5GVPu/HrRJU+eAJJto74vm+6vP7zDn2YV2gJ1w18O/37nc7W/bVCgZJlhZ3cwew==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.48.0",
|
||||
"@sentry/types": "7.48.0",
|
||||
"@sentry/utils": "7.48.0",
|
||||
"@sentry/core": "7.49.0",
|
||||
"@sentry/types": "7.49.0",
|
||||
"@sentry/utils": "7.49.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2968,15 +2968,15 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.48.0.tgz",
|
||||
"integrity": "sha512-tdx/2nhuiykncmXFlV4Dpp+Hxgt/v31LiyXE79IcM560wc+QmWKtzoW9azBWQ0xt5KOO3ERMib9qPE4/ql1/EQ==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.49.0.tgz",
|
||||
"integrity": "sha512-x2DekKkQoY7/dhBzE4J25mdQ978NtPBTVQb+uZqlF/t5mp4K44TAszmPqy8lC/CmVHkp7qcpRGSCIzeboUL4KA==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/tracing": "7.48.0",
|
||||
"@sentry/core": "7.48.0",
|
||||
"@sentry/replay": "7.48.0",
|
||||
"@sentry/types": "7.48.0",
|
||||
"@sentry/utils": "7.48.0",
|
||||
"@sentry-internal/tracing": "7.49.0",
|
||||
"@sentry/core": "7.49.0",
|
||||
"@sentry/replay": "7.49.0",
|
||||
"@sentry/types": "7.49.0",
|
||||
"@sentry/utils": "7.49.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -2989,12 +2989,12 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.48.0.tgz",
|
||||
"integrity": "sha512-8FYuJTMpyuxRZvlen3gQ3rpOtVInSDmSyXqWEhCLuG/w34AtWoTiW7G516rsAAh6Hy1TP91GooMWbonP3XQNTQ==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.49.0.tgz",
|
||||
"integrity": "sha512-AlSnCYgfEbvK8pkNluUkmdW/cD9UpvOVCa+ERQswXNRkAv5aDGCL6Ihv6fnIajE++BYuwZh0+HwZUBVKTFzoZg==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.48.0",
|
||||
"@sentry/utils": "7.48.0",
|
||||
"@sentry/types": "7.49.0",
|
||||
"@sentry/utils": "7.49.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -3007,43 +3007,43 @@
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@sentry/replay": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.48.0.tgz",
|
||||
"integrity": "sha512-8fRHMGJ0NJeIZi6UucxUTvfDPaBa7+jU1kCTLjCcuH3X/UVz5PtGLMtFSO5U8HP+mUDlPs97MP1uoDvMa4S2Ng==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.49.0.tgz",
|
||||
"integrity": "sha512-UY3bHoBDPOu4Dpq3m3oxNjLrq09NiFVYUfrTN4QOq1Am2SA04XbuCj/YZ+jNVy/NrFtoz9cTovK6oQbNw53jog==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.48.0",
|
||||
"@sentry/types": "7.48.0",
|
||||
"@sentry/utils": "7.48.0"
|
||||
"@sentry/core": "7.49.0",
|
||||
"@sentry/types": "7.49.0",
|
||||
"@sentry/utils": "7.49.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/tracing": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.48.0.tgz",
|
||||
"integrity": "sha512-X6w74Av0fyayNicKIlwL1IdpZ3O0ETQjyYXCDTwHoJL71ojrgrL5vdiNz8WwbPONTnqu98HehPYL/z3DCCKVbw==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.49.0.tgz",
|
||||
"integrity": "sha512-RtyTt1DvX7s1M2ca9qnevOkuwn8HjbKXrSVHtMbQYoT3uGvjT8Pm71D5WtWMWH2QLpFgcqQq/1ifZBUAG4Y7qA==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/tracing": "7.48.0"
|
||||
"@sentry-internal/tracing": "7.49.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.48.0.tgz",
|
||||
"integrity": "sha512-kkAszZwQ5/v4n7Yyw/DPNRWx7h724mVNRGZIJa9ggUMvTgMe7UKCZZ5wfQmYiKVlGbwd9pxXAcP8Oq15EbByFQ==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.49.0.tgz",
|
||||
"integrity": "sha512-9yXXh7iv76+O6h2ONUVx0wsL1auqJFWez62mTjWk4350SgMmWp/zUkBxnVXhmcYqscz/CepC+Loz9vITLXtgxg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "7.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.48.0.tgz",
|
||||
"integrity": "sha512-d977sghkFVMfld0LrEyyY2gYrfayLPdDEpUDT+hg5y79r7zZDCFyHtdB86699E5K89MwDZahW7Erk+a1nk4x5w==",
|
||||
"version": "7.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.49.0.tgz",
|
||||
"integrity": "sha512-JdC9yGnOgev4ISJVwmIoFsk8Zx0psDZJAj2DV7x4wMZsO6QK+YjC7G3mUED/S5D5lsrkBZ/3uvQQhr8DQI4UcQ==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.48.0",
|
||||
"@sentry/types": "7.49.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -3379,14 +3379,14 @@
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz",
|
||||
"integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.0.tgz",
|
||||
"integrity": "sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "5.58.0",
|
||||
"@typescript-eslint/type-utils": "5.58.0",
|
||||
"@typescript-eslint/utils": "5.58.0",
|
||||
"@typescript-eslint/scope-manager": "5.59.0",
|
||||
"@typescript-eslint/type-utils": "5.59.0",
|
||||
"@typescript-eslint/utils": "5.59.0",
|
||||
"debug": "^4.3.4",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"ignore": "^5.2.0",
|
||||
@ -3426,13 +3426,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.58.0.tgz",
|
||||
"integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.0.tgz",
|
||||
"integrity": "sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.58.0",
|
||||
"@typescript-eslint/types": "5.58.0",
|
||||
"@typescript-eslint/typescript-estree": "5.58.0",
|
||||
"@typescript-eslint/scope-manager": "5.59.0",
|
||||
"@typescript-eslint/types": "5.59.0",
|
||||
"@typescript-eslint/typescript-estree": "5.59.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -3452,12 +3452,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz",
|
||||
"integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.0.tgz",
|
||||
"integrity": "sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.58.0",
|
||||
"@typescript-eslint/visitor-keys": "5.58.0"
|
||||
"@typescript-eslint/types": "5.59.0",
|
||||
"@typescript-eslint/visitor-keys": "5.59.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@ -3468,12 +3468,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz",
|
||||
"integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz",
|
||||
"integrity": "sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.58.0",
|
||||
"@typescript-eslint/utils": "5.58.0",
|
||||
"@typescript-eslint/typescript-estree": "5.59.0",
|
||||
"@typescript-eslint/utils": "5.59.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@ -3494,9 +3494,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz",
|
||||
"integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.0.tgz",
|
||||
"integrity": "sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
@ -3506,12 +3506,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz",
|
||||
"integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz",
|
||||
"integrity": "sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.58.0",
|
||||
"@typescript-eslint/visitor-keys": "5.58.0",
|
||||
"@typescript-eslint/types": "5.59.0",
|
||||
"@typescript-eslint/visitor-keys": "5.59.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -3532,9 +3532,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
|
||||
"integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz",
|
||||
"integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@ -3546,16 +3546,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz",
|
||||
"integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.0.tgz",
|
||||
"integrity": "sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA==",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.58.0",
|
||||
"@typescript-eslint/types": "5.58.0",
|
||||
"@typescript-eslint/typescript-estree": "5.58.0",
|
||||
"@typescript-eslint/scope-manager": "5.59.0",
|
||||
"@typescript-eslint/types": "5.59.0",
|
||||
"@typescript-eslint/typescript-estree": "5.59.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"semver": "^7.3.7"
|
||||
},
|
||||
@ -3571,9 +3571,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/semver": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
|
||||
"integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz",
|
||||
"integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@ -3585,11 +3585,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.58.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz",
|
||||
"integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==",
|
||||
"version": "5.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.0.tgz",
|
||||
"integrity": "sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.58.0",
|
||||
"@typescript-eslint/types": "5.59.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -5255,14 +5255,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz",
|
||||
"integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==",
|
||||
"version": "8.39.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz",
|
||||
"integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.4.0",
|
||||
"@eslint/eslintrc": "^2.0.2",
|
||||
"@eslint/js": "8.38.0",
|
||||
"@eslint/js": "8.39.0",
|
||||
"@humanwhocodes/config-array": "^0.11.8",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
@ -5272,7 +5272,7 @@
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-scope": "^7.2.0",
|
||||
"eslint-visitor-keys": "^3.4.0",
|
||||
"espree": "^9.5.1",
|
||||
"esquery": "^1.4.2",
|
||||
@ -5330,9 +5330,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-lit": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.8.2.tgz",
|
||||
"integrity": "sha512-4mOGcSRNEPMh7AN2F7Iy6no36nuFgyYOsnTRhFw1k8xyy1Zm6QOp788ywDvJqy+eelFbLPBhq20Qr55a887Dmw==",
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.8.3.tgz",
|
||||
"integrity": "sha512-wmeYfBnWPUChbdZagOhG519gaWz9Q7OGT/nCx3YVHuCCrW9q9u0p/IQueQeoaMojUqOSgM/22oSDOaBruYGqag==",
|
||||
"dependencies": {
|
||||
"parse5": "^6.0.1",
|
||||
"parse5-htmlparser2-tree-adapter": "^6.0.1",
|
||||
@ -5425,15 +5425,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/eslint-scope": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
|
||||
"integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz",
|
||||
"integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==",
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/estraverse": {
|
||||
@ -8117,9 +8120,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.7",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
|
||||
"integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
@ -8216,9 +8219,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pyright": {
|
||||
"version": "1.1.303",
|
||||
"resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.303.tgz",
|
||||
"integrity": "sha512-uwJdp3KRidmpIgKKQtNL17F2noF2PsK6bxqd7WWrQE1AfCHI0j53B9lro63S/9oWWu18xfgTI4IqKO5S1srxhA==",
|
||||
"version": "1.1.304",
|
||||
"resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.304.tgz",
|
||||
"integrity": "sha512-b7q53RytKcu/JIzBDfT4po1Uj1eyjXP4wHcWEOXNkWt8+fS8X6lZhRjPe5yzfPvh/2heTKcIEwY+J/VuMobuyw==",
|
||||
"bin": {
|
||||
"pyright": "index.js",
|
||||
"pyright-langserver": "langserver.index.js"
|
||||
|
@ -59,14 +59,14 @@
|
||||
"@babel/preset-env": "^7.21.4",
|
||||
"@babel/preset-typescript": "^7.21.4",
|
||||
"@codemirror/lang-html": "^6.4.3",
|
||||
"@codemirror/lang-javascript": "^6.1.6",
|
||||
"@codemirror/lang-javascript": "^6.1.7",
|
||||
"@codemirror/lang-python": "^6.1.2",
|
||||
"@codemirror/lang-xml": "^6.0.2",
|
||||
"@codemirror/legacy-modes": "^6.3.2",
|
||||
"@codemirror/theme-one-dark": "^6.1.1",
|
||||
"@formatjs/intl-listformat": "^7.1.9",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@formatjs/intl-listformat": "^7.2.1",
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@goauthentik/api": "^2023.4.0-1681471246",
|
||||
"@goauthentik/api": "^2023.4.1-1681914191",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||
"@lingui/cli": "^3.17.2",
|
||||
@ -79,15 +79,15 @@
|
||||
"@rollup/plugin-node-resolve": "^15.0.2",
|
||||
"@rollup/plugin-replace": "^5.0.2",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@sentry/browser": "^7.48.0",
|
||||
"@sentry/tracing": "^7.48.0",
|
||||
"@sentry/browser": "^7.49.0",
|
||||
"@sentry/tracing": "^7.49.0",
|
||||
"@squoosh/cli": "^0.7.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||
"@types/chart.js": "^2.9.37",
|
||||
"@types/codemirror": "5.60.7",
|
||||
"@types/grecaptcha": "^3.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
||||
"@typescript-eslint/parser": "^5.58.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
@ -98,16 +98,16 @@
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"core-js": "^3.30.1",
|
||||
"country-flag-icons": "^1.5.7",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.8",
|
||||
"eslint-plugin-lit": "^1.8.2",
|
||||
"eslint-plugin-lit": "^1.8.3",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lit": "^2.7.2",
|
||||
"mermaid": "^10.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"prettier": "^2.8.7",
|
||||
"pyright": "^1.1.303",
|
||||
"prettier": "^2.8.8",
|
||||
"pyright": "^1.1.304",
|
||||
"rapidoc": "^9.3.4",
|
||||
"rollup": "^2.79.1",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
|
@ -60,7 +60,7 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
||||
});
|
||||
}
|
||||
const c = await config();
|
||||
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
|
||||
if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
const icon = this.getFormFiles()["metaIcon"];
|
||||
if (icon || this.clearIcon) {
|
||||
await new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIconCreate({
|
||||
@ -195,7 +195,7 @@ export class ApplicationForm extends ModelForm<Application, string> {
|
||||
${t`If checked, the launch URL will open in a new browser tab or window from the user's application library.`}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia)
|
||||
${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia)
|
||||
? html`<ak-form-element-horizontal label=${t`Icon`} name="metaIcon">
|
||||
<input type="file" value="" class="pf-c-form-control" />
|
||||
${this.instance?.metaIcon
|
||||
|
@ -126,7 +126,11 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
|
||||
row(item: BlueprintInstance): TemplateResult[] {
|
||||
let description = undefined;
|
||||
const descKey = "blueprints.goauthentik.io/description";
|
||||
if (Object.hasOwn(item.metadata?.labels, descKey)) {
|
||||
if (
|
||||
item.metadata &&
|
||||
item.metadata.labels &&
|
||||
Object.hasOwn(item.metadata?.labels, descKey)
|
||||
) {
|
||||
description = item.metadata?.labels[descKey];
|
||||
}
|
||||
return [
|
||||
|
@ -95,17 +95,25 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
|
||||
if (item.managed && item.managed.startsWith("goauthentik.io/crypto/discovered")) {
|
||||
managedSubText = t`Managed by authentik (Discovered)`;
|
||||
}
|
||||
let color = PFColor.Green;
|
||||
if (item.certExpiry) {
|
||||
const now = new Date();
|
||||
const inAMonth = new Date();
|
||||
inAMonth.setDate(inAMonth.getDate() + 30);
|
||||
if (item.certExpiry <= inAMonth) {
|
||||
color = PFColor.Orange;
|
||||
}
|
||||
if (item.certExpiry <= now) {
|
||||
color = PFColor.Red;
|
||||
}
|
||||
}
|
||||
return [
|
||||
html`<div>${item.name}</div>
|
||||
${item.managed ? html`<small>${managedSubText}</small>` : html``}`,
|
||||
html`<ak-label color=${item.privateKeyAvailable ? PFColor.Green : PFColor.Grey}>
|
||||
${item.privateKeyAvailable ? t`Yes (${item.privateKeyType?.toUpperCase()})` : t`No`}
|
||||
</ak-label>`,
|
||||
html`<ak-label
|
||||
color=${item.certExpiry || new Date() > new Date() ? PFColor.Green : PFColor.Orange}
|
||||
>
|
||||
${item.certExpiry?.toLocaleString()}
|
||||
</ak-label>`,
|
||||
html`<ak-label color=${color}> ${item.certExpiry?.toLocaleString()} </ak-label>`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${t`Update`} </span>
|
||||
<span slot="header"> ${t`Update Certificate-Key Pair`} </span>
|
||||
|
@ -56,7 +56,7 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||
});
|
||||
}
|
||||
const c = await config();
|
||||
if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) {
|
||||
if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
const icon = this.getFormFiles()["background"];
|
||||
if (icon || this.clearBackground) {
|
||||
await new FlowsApi(DEFAULT_CONFIG).flowsInstancesSetBackgroundCreate({
|
||||
@ -315,7 +315,7 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||
</option>
|
||||
</select>
|
||||
</ak-form-element-horizontal>
|
||||
${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia)
|
||||
${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanSaveMedia)
|
||||
? html`<ak-form-element-horizontal label=${t`Background`} name="background">
|
||||
<input type="file" value="" class="pf-c-form-control" />
|
||||
${this.instance?.background
|
||||
|
@ -50,9 +50,6 @@ export class FlowListPage extends TablePage<Flow> {
|
||||
|
||||
groupBy(items: Flow[]): [string, Flow[]][] {
|
||||
return groupBy(items, (flow) => {
|
||||
if (!flow.designation) {
|
||||
return "";
|
||||
}
|
||||
return DesignationToLabel(flow.designation);
|
||||
});
|
||||
}
|
||||
|
@ -47,11 +47,12 @@ export class StageBindingForm extends ModelForm<FlowStageBinding, string> {
|
||||
return t`Successfully created binding.`;
|
||||
}
|
||||
}
|
||||
|
||||
send(data: FlowStageBinding): Promise<unknown> {
|
||||
if (this.instance?.pk) {
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsUpdate({
|
||||
return new FlowsApi(DEFAULT_CONFIG).flowsBindingsPartialUpdate({
|
||||
fsbUuid: this.instance.pk,
|
||||
flowStageBindingRequest: data,
|
||||
patchedFlowStageBindingRequest: data,
|
||||
});
|
||||
} else {
|
||||
if (this.targetPk) {
|
||||
|
@ -85,7 +85,7 @@ export class OutpostServiceConnectionListPage extends TablePage<ServiceConnectio
|
||||
html`<ak-label color=${item.local ? PFColor.Grey : PFColor.Green}>
|
||||
${item.local ? t`Yes` : t`No`}
|
||||
</ak-label>`,
|
||||
html`${itemState.healthy
|
||||
html`${itemState?.healthy
|
||||
? html`<ak-label color=${PFColor.Green}>${ifDefined(itemState.version)}</ak-label>`
|
||||
: html`<ak-label color=${PFColor.Red}>${t`Unhealthy`}</ak-label>`}`,
|
||||
html` <ak-forms-modal>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user