mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
Merge branch 'main' into stages/user_login/dbsc
This commit is contained in:
@@ -20,12 +20,22 @@ runs:
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ inputs.token }}
|
||||
# Untrusted/event-derived values are passed via the environment (never
|
||||
# interpolated into the script body) to avoid template injection.
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
LABEL_NAME_CTX: ${{ github.event.label.name }}
|
||||
PR_NUMBER_CTX: ${{ github.event.pull_request.number }}
|
||||
MERGE_COMMIT_SHA_CTX: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
EVENT_ACTION: ${{ github.event.action }}
|
||||
PR_MERGED_CTX: ${{ github.event.pull_request.merged }}
|
||||
run: |
|
||||
set -e -o pipefail
|
||||
# For issues events, check if it's actually a PR
|
||||
if [ "${{ github.event_name }}" = "issues" ]; then
|
||||
if [ "$EVENT_NAME" = "issues" ]; then
|
||||
# Check if this issue is actually a PR
|
||||
PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }} 2>/dev/null || echo "null")
|
||||
PR_DATA=$(gh api "repos/${REPOSITORY}/pulls/${ISSUE_NUMBER}" 2>/dev/null || echo "null")
|
||||
if [ "$PR_DATA" = "null" ]; then
|
||||
echo "should_run=false" >> $GITHUB_OUTPUT
|
||||
echo "reason=not_a_pr" >> $GITHUB_OUTPUT
|
||||
@@ -35,11 +45,11 @@ runs:
|
||||
|
||||
# Get PR data
|
||||
PR_MERGED=$(echo "$PR_DATA" | jq -r '.merged')
|
||||
PR_NUMBER="${{ github.event.issue.number }}"
|
||||
PR_NUMBER="$ISSUE_NUMBER"
|
||||
MERGE_COMMIT_SHA=$(echo "$PR_DATA" | jq -r '.merge_commit_sha')
|
||||
|
||||
# Check if it's a backport label
|
||||
LABEL_NAME="${{ github.event.label.name }}"
|
||||
LABEL_NAME="$LABEL_NAME_CTX"
|
||||
if [[ "$LABEL_NAME" =~ ^backport/(.+)$ ]]; then
|
||||
if [ "$PR_MERGED" = "true" ]; then
|
||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
||||
@@ -61,11 +71,11 @@ runs:
|
||||
fi
|
||||
|
||||
# For pull_request and pull_request_target events
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
MERGE_COMMIT_SHA="${{ github.event.pull_request.merge_commit_sha }}"
|
||||
PR_NUMBER="$PR_NUMBER_CTX"
|
||||
MERGE_COMMIT_SHA="$MERGE_COMMIT_SHA_CTX"
|
||||
|
||||
# Case 1: PR was just merged (closed + merged = true)
|
||||
if [ "${{ github.event.action }}" = "closed" ] && [ "${{ github.event.pull_request.merged }}" = "true" ]; then
|
||||
if [ "$EVENT_ACTION" = "closed" ] && [ "$PR_MERGED_CTX" = "true" ]; then
|
||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
||||
echo "reason=pr_merged" >> $GITHUB_OUTPUT
|
||||
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
@@ -74,12 +84,12 @@ runs:
|
||||
fi
|
||||
|
||||
# Case 2: Label was added
|
||||
if [ "${{ github.event.action }}" = "labeled" ]; then
|
||||
LABEL_NAME="${{ github.event.label.name }}"
|
||||
if [ "$EVENT_ACTION" = "labeled" ]; then
|
||||
LABEL_NAME="$LABEL_NAME_CTX"
|
||||
# Check if it's a backport label
|
||||
if [[ "$LABEL_NAME" =~ ^backport/(.+)$ ]]; then
|
||||
# Check if PR is already merged
|
||||
if [ "${{ github.event.pull_request.merged }}" = "true" ]; then
|
||||
if [ "$PR_MERGED_CTX" = "true" ]; then
|
||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
||||
echo "reason=label_added_to_merged_pr" >> $GITHUB_OUTPUT
|
||||
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
@@ -117,17 +127,14 @@ runs:
|
||||
GITHUB_TOKEN: ${{ inputs.token }}
|
||||
PR_NUMBER: ${{ steps.should_run.outputs.pr_number }}
|
||||
REASON: ${{ steps.should_run.outputs.reason }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
LABEL_NAME_CTX: ${{ github.event.label.name }}
|
||||
run: |
|
||||
set -e -o pipefail
|
||||
|
||||
# Determine which labels to process
|
||||
if [ "${REASON}" = "label_added_to_merged_pr" ]; then
|
||||
# Only process the specific label that was just added
|
||||
if [ "${{ github.event_name }}" = "issues" ]; then
|
||||
LABEL_NAME="${{ github.event.label.name }}"
|
||||
else
|
||||
LABEL_NAME="${{ github.event.label.name }}"
|
||||
fi
|
||||
LABEL_NAME="$LABEL_NAME_CTX"
|
||||
|
||||
if [[ "$LABEL_NAME" =~ ^backport/(.+)$ ]]; then
|
||||
echo "labels=$LABEL_NAME" >> $GITHUB_OUTPUT
|
||||
@@ -150,10 +157,11 @@ runs:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
LABELS: '${{ steps.pr_details.outputs.labels }}'
|
||||
REASON: '${{ steps.should_run.outputs.reason }}'
|
||||
run: |
|
||||
set -e -o pipefail
|
||||
|
||||
echo "Processing PR #$PR_NUMBER (reason: ${{ steps.should_run.outputs.reason }})"
|
||||
echo "Processing PR #$PR_NUMBER (reason: ${REASON})"
|
||||
echo "Found backport labels: $LABELS"
|
||||
|
||||
# Process each backport label
|
||||
|
||||
@@ -37,7 +37,7 @@ runs:
|
||||
sudo rsync -a --delete /tmp/empty/ /usr/local/lib/android/
|
||||
- name: Install uv
|
||||
if: ${{ contains(inputs.dependencies, 'python') }}
|
||||
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v5
|
||||
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v5
|
||||
with:
|
||||
enable-cache: true
|
||||
- name: Setup python
|
||||
@@ -64,7 +64,7 @@ runs:
|
||||
rustflags: ""
|
||||
- name: Setup rust dependencies
|
||||
if: ${{ contains(inputs.dependencies, 'rust') }}
|
||||
uses: taiki-e/install-action@ec28e287910af896fd98e04056d31fa68607e7ad # v2
|
||||
uses: taiki-e/install-action@56545b37b57562edd73171cb6c62cc509db4c34e # v2
|
||||
with:
|
||||
tool: cargo-deny cargo-machete cargo-llvm-cov nextest
|
||||
- name: Setup node (root, web)
|
||||
@@ -79,7 +79,7 @@ runs:
|
||||
go-version-file: "${{ inputs.working-directory }}go.mod"
|
||||
- name: Setup docker cache
|
||||
if: ${{ contains(inputs.dependencies, 'runtime') }}
|
||||
uses: AndreKurait/docker-cache@0fe76702a40db986d9663c24954fc14c6a6031b7
|
||||
uses: AndreKurait/docker-cache@7a3887908bdb97935395833df69b060cfcca0f7f
|
||||
with:
|
||||
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
|
||||
- name: Setup dependencies
|
||||
|
||||
@@ -10,12 +10,12 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5
|
||||
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v5
|
||||
with:
|
||||
files: ${{ inputs.files }}
|
||||
flags: ${{ inputs.flags }}
|
||||
use_oidc: true
|
||||
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5
|
||||
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v5
|
||||
with:
|
||||
files: ${{ inputs.files }}
|
||||
flags: ${{ inputs.flags }}
|
||||
|
||||
@@ -307,6 +307,10 @@ updates:
|
||||
- "lxml"
|
||||
- "psycopg"
|
||||
- "pyopenssl"
|
||||
groups:
|
||||
types:
|
||||
patterns:
|
||||
- types-*
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,38 +1,26 @@
|
||||
<!--
|
||||
👋 Hi there! Welcome.
|
||||
👋 Hi there! Welcome. Please check the contributing guidelines: https://docs.goauthentik.io/docs/developer-docs/#how-can-i-contribute
|
||||
|
||||
Please check the Contributing guidelines: https://docs.goauthentik.io/docs/developer-docs/#how-can-i-contribute
|
||||
|
||||
⚠️ IMPORTANT: Make sure you are opening this PR from a FEATURE BRANCH, not from your main branch!
|
||||
If you opened this PR from your main branch, please close it and create a new feature branch instead.
|
||||
For more information, see: https://docs.goauthentik.io/developer-docs/contributing/#always-use-feature-branches
|
||||
⚠️ Open this PR from a feature branch, not from main: https://docs.goauthentik.io/developer-docs/contributing/#always-use-feature-branches
|
||||
-->
|
||||
|
||||
## Details
|
||||
|
||||
<!--
|
||||
Explain what this PR changes, what the rationale behind the change is, if any new requirements are introduced or any breaking changes caused by this PR.
|
||||
### What does this PR change?
|
||||
|
||||
Ideally also link an Issue for context that this PR will close using `closes #`
|
||||
### Why is this change needed?
|
||||
|
||||
### How was this tested?
|
||||
|
||||
### Linked issues
|
||||
|
||||
<!--
|
||||
Use `closes #N` to auto-close an issue on merge. Use `refs #N` for related issues that this PR does not close.
|
||||
-->
|
||||
REPLACE ME
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Local tests pass (`ak test authentik/`)
|
||||
- [ ] The code has been formatted (`make lint-fix`)
|
||||
|
||||
If an API change has been made
|
||||
|
||||
- [ ] The API schema and clients have been updated (`make gen`)
|
||||
|
||||
If changes to the frontend have been made
|
||||
|
||||
- [ ] The code has been formatted (`make web`)
|
||||
|
||||
If applicable
|
||||
|
||||
- [ ] The documentation has been updated
|
||||
- [ ] The documentation has been formatted (`make docs`)
|
||||
- [ ] The project has been linted, built, and tested (`make all`)
|
||||
- [ ] The documentation has been updated and formatted (`make docs`)
|
||||
|
||||
@@ -42,9 +42,9 @@ jobs:
|
||||
# Needed for checkout
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -56,13 +56,13 @@ jobs:
|
||||
release: ${{ inputs.release }}
|
||||
- name: Login to Docker Hub
|
||||
if: ${{ inputs.registry_dockerhub }}
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_CORP_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
|
||||
- name: Login to GitHub Container Registry
|
||||
if: ${{ inputs.registry_ghcr }}
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
@@ -71,14 +71,14 @@ jobs:
|
||||
with:
|
||||
working-directory: web
|
||||
dependencies: "monorepo"
|
||||
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
- name: Generate API Clients
|
||||
run: |
|
||||
make gen-client-ts
|
||||
- name: Build Docker Image
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
id: push
|
||||
with:
|
||||
context: .
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
with:
|
||||
image_name: ${{ inputs.image_name }}
|
||||
image_arch: arm64
|
||||
runs-on: ubuntu-22.04-arm
|
||||
runs-on: ubuntu-24.04-arm
|
||||
registry_dockerhub: ${{ inputs.registry_dockerhub }}
|
||||
registry_ghcr: ${{ inputs.registry_ghcr }}
|
||||
release: ${{ inputs.release }}
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
tags: ${{ steps.ev.outputs.imageTagsJSON }}
|
||||
shouldPush: ${{ steps.ev.outputs.shouldPush }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
matrix:
|
||||
tag: ${{ fromJson(needs.get-tags.outputs.tags) }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -79,18 +79,18 @@ jobs:
|
||||
image-name: ${{ inputs.image_name }}
|
||||
- name: Login to Docker Hub
|
||||
if: ${{ inputs.registry_dockerhub }}
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_CORP_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
|
||||
- name: Login to GitHub Container Registry
|
||||
if: ${{ inputs.registry_ghcr }}
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: int128/docker-manifest-create-action@fa55f72001a6c74b0f4997dca65c70d334905180 # v2
|
||||
- uses: int128/docker-manifest-create-action@126c2b2195800ebc112cffe9ad6c2e2cce16eff2 # v2
|
||||
id: build
|
||||
with:
|
||||
tags: ${{ matrix.tag }}
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
command:
|
||||
- prettier-check
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: website
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: website
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
- lint
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v5
|
||||
with:
|
||||
name: api-docs
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
check-changes-applied:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/setup-node
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: generate docs
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
command:
|
||||
- prettier-check
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: website
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
name: Setup Node.js
|
||||
with:
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: website
|
||||
@@ -61,13 +61,13 @@ jobs:
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -77,14 +77,14 @@ jobs:
|
||||
image-name: ghcr.io/goauthentik/dev-docs
|
||||
- name: Login to Container Registry
|
||||
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build Docker Image
|
||||
id: push
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
with:
|
||||
tags: ${{ steps.ev.outputs.imageTags }}
|
||||
file: website/Dockerfile
|
||||
|
||||
@@ -19,20 +19,15 @@ jobs:
|
||||
matrix:
|
||||
version:
|
||||
- docs
|
||||
- version-2025-12
|
||||
- version-2026-2
|
||||
- version-2026-5
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- run: |
|
||||
set -euo pipefail
|
||||
current="$(pwd)"
|
||||
dir="/tmp/authentik/${{ matrix.version }}"
|
||||
# 2025.12 still serves the legacy docker-compose filename; newer sites use compose.yml.
|
||||
compose_path="compose.yml"
|
||||
if [ "${{ matrix.version }}" = "version-2025-12" ]; then
|
||||
compose_path="docker-compose.yml"
|
||||
fi
|
||||
mkdir -p "${dir}/lifecycle/container"
|
||||
cd "${dir}"
|
||||
wget "https://${{ matrix.version }}.goauthentik.io/${compose_path}" -O "${dir}/lifecycle/container/compose.yml"
|
||||
wget "https://${{ matrix.version }}.goauthentik.io/compose.yml" -O "${dir}/lifecycle/container/compose.yml"
|
||||
"${current}/scripts/test_docker.sh"
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
deps: rust-nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
test-gen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Setup authentik env
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
test-migrations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: run migrations
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
- 18-alpine
|
||||
run_id: [1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: checkout stable
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
- 18-alpine
|
||||
run_id: [1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: Create k8s Kind Cluster
|
||||
@@ -252,7 +252,7 @@ jobs:
|
||||
glob: tests/e2e/test_endpoints_*
|
||||
profiles: selenium
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: Setup e2e env
|
||||
@@ -306,7 +306,7 @@ jobs:
|
||||
- name: ssf_transmitter
|
||||
glob: tests/openid_conformance/test_ssf_transmitter.py
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: Setup e2e env (chrome, etc)
|
||||
@@ -348,7 +348,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -407,7 +407,7 @@ jobs:
|
||||
pull-requests: write
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: prepare variables
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
lint-golint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
mkdir -p website/help
|
||||
touch web/dist/test website/help/test
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v8
|
||||
uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v8
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout 5000s --verbose
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
test-unittest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
@@ -82,13 +82,13 @@ jobs:
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -98,14 +98,14 @@ jobs:
|
||||
image-name: ghcr.io/goauthentik/dev-${{ matrix.type }}
|
||||
- name: Login to Container Registry
|
||||
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build Docker Image
|
||||
id: push
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
with:
|
||||
tags: ${{ steps.ev.outputs.imageTags }}
|
||||
file: lifecycle/container/${{ matrix.type }}.Dockerfile
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
goos: [linux]
|
||||
goarch: [amd64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: web
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: web
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
working-directory: web
|
||||
|
||||
@@ -29,16 +29,16 @@ jobs:
|
||||
github.event.pull_request.head.repo.full_name == github.repository)
|
||||
steps:
|
||||
- id: generate_token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- name: Compress images
|
||||
id: compress
|
||||
uses: calibreapp/image-actions@e2cc8db5d49c849e00844dfebf01438318e96fa2 # main
|
||||
uses: calibreapp/image-actions@9d037c06280028c110ff61c433ad4dc7d33c3c43 # main
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
compressOnly: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
@@ -16,11 +16,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: generate_token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- name: Setup authentik env
|
||||
|
||||
@@ -10,14 +10,14 @@ jobs:
|
||||
steps:
|
||||
- id: app-token
|
||||
name: Generate app token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
if: ${{ env.GH_APP_ID != '' }}
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
env:
|
||||
GH_APP_ID: ${{ secrets.GH_APP_ID }}
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
if: ${{ steps.app-token.outcome != 'skipped' }}
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
|
||||
@@ -16,12 +16,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: generate_token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- name: Delete 'dev' containers older than a week
|
||||
uses: snok/container-retention-policy@3b0972b2276b171b212f8c4efbca59ebba26eceb # v3.0.1
|
||||
uses: snok/container-retention-policy@d3bdcf5ce9b05f685154e4a16c39233b245e3d53 # v3.1.0
|
||||
with:
|
||||
image-names: dev-server,dev-ldap,dev-proxy
|
||||
image-tags: "!gh-next,!gh-main"
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- packages/logger-js
|
||||
- packages/esbuild-plugin-live-reload
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- uses: ./.github/actions/setup-node
|
||||
|
||||
@@ -24,14 +24,14 @@ jobs:
|
||||
language: ["go", "javascript", "python"]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4.35.4
|
||||
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v4.35.4
|
||||
uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4.35.4
|
||||
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: QA - Dependency review
|
||||
|
||||
# Blocks PRs that introduce a dependency with a known vulnerability above
|
||||
# the configured severity threshold. Covers every ecosystem GitHub's
|
||||
# Advisory Database supports — for this repo that's npm, Go modules,
|
||||
# Python (pip/uv), Cargo, and GitHub Actions.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
name: dependency-review
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
||||
with:
|
||||
# Block PRs that introduce a *new* dependency with a known
|
||||
# high/critical vuln. We don't fail on existing vulns — those are
|
||||
# surfaced separately via Dependabot.
|
||||
fail-on-severity: high
|
||||
# Surface a summary comment on the PR itself, in addition to the
|
||||
# check status, so reviewers can see the diff at a glance.
|
||||
comment-summary-in-pr: on-failure
|
||||
@@ -26,5 +26,5 @@ jobs:
|
||||
image: semgrep/semgrep
|
||||
if: (github.actor != 'dependabot[bot]')
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- run: semgrep ci
|
||||
|
||||
@@ -29,12 +29,12 @@ jobs:
|
||||
steps:
|
||||
- id: app-token
|
||||
name: Generate app token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: main
|
||||
token: "${{ steps.app-token.outputs.token }}"
|
||||
@@ -57,12 +57,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: generate_token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: internal-production
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: main
|
||||
- run: |
|
||||
|
||||
@@ -31,11 +31,11 @@ jobs:
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -44,14 +44,14 @@ jobs:
|
||||
with:
|
||||
image-name: ghcr.io/goauthentik/docs
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build Docker Image
|
||||
id: push
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
with:
|
||||
tags: ${{ steps.ev.outputs.imageTags }}
|
||||
file: website/Dockerfile
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
- radius
|
||||
- rac
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
@@ -91,9 +91,9 @@ jobs:
|
||||
with:
|
||||
working-directory: web
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -102,18 +102,18 @@ jobs:
|
||||
with:
|
||||
image-name: ghcr.io/goauthentik/${{ matrix.type }},authentik/${{ matrix.type }}
|
||||
- name: Docker Login Registry
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_CORP_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build Docker Image
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
id: push
|
||||
with:
|
||||
push: true
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
goos: [linux, darwin]
|
||||
goarch: [amd64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
@@ -182,8 +182,8 @@ jobs:
|
||||
AWS_REGION: eu-central-1
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0
|
||||
with:
|
||||
role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik"
|
||||
aws-region: ${{ env.AWS_REGION }}
|
||||
@@ -198,7 +198,7 @@ jobs:
|
||||
- build-outpost-binary
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: Run test suite in final docker images
|
||||
run: |
|
||||
echo "PG_PASS=$(openssl rand 32 | base64 -w 0)" >> lifecycle/container/.env
|
||||
@@ -214,7 +214,7 @@ jobs:
|
||||
- build-outpost-binary
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
- name: prepare variables
|
||||
uses: ./.github/actions/docker-push-variables
|
||||
id: ev
|
||||
@@ -228,7 +228,7 @@ jobs:
|
||||
container=$(docker container create ${{ steps.ev.outputs.imageMainName }})
|
||||
docker cp ${container}:web/ .
|
||||
- name: Create a Sentry.io release
|
||||
uses: getsentry/action-release@5657c9e888b4e2cc85f4d29143ea4131fde4a73a # v3
|
||||
uses: getsentry/action-release@ff07929a6537bac57790c3451cf4d364aca38528 # v3
|
||||
continue-on-error: true
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
needs:
|
||||
- check-inputs
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: "version-${{ needs.check-inputs.outputs.major_version }}"
|
||||
- name: Setup authentik env
|
||||
@@ -67,16 +67,16 @@ jobs:
|
||||
steps:
|
||||
- id: app-token
|
||||
name: Generate app token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- id: get-user-id
|
||||
name: Get GitHub app user ID
|
||||
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
ref: "version-${{ needs.check-inputs.outputs.major_version }}"
|
||||
token: "${{ steps.app-token.outputs.token }}"
|
||||
@@ -119,9 +119,9 @@ jobs:
|
||||
steps:
|
||||
- id: app-token
|
||||
name: Generate app token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
repositories: helm
|
||||
- id: get-user-id
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
repository: "${{ github.repository_owner }}/helm"
|
||||
token: "${{ steps.app-token.outputs.token }}"
|
||||
@@ -161,9 +161,9 @@ jobs:
|
||||
steps:
|
||||
- id: app-token
|
||||
name: Generate app token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
repositories: version
|
||||
- id: get-user-id
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: "${{ steps.app-token.outputs.token }}"
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
with:
|
||||
repository: "${{ github.repository_owner }}/version"
|
||||
token: "${{ steps.app-token.outputs.token }}"
|
||||
|
||||
@@ -15,11 +15,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: generate_token
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
|
||||
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10
|
||||
with:
|
||||
repo-token: ${{ steps.generate_token.outputs.token }}
|
||||
days-before-stale: 60
|
||||
|
||||
@@ -21,15 +21,15 @@ jobs:
|
||||
steps:
|
||||
- id: generate_token
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v2
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
client-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v5
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
- name: Setup authentik env
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
+9
-5
@@ -20,6 +20,10 @@ corepack.tgz
|
||||
.cspellcache
|
||||
cspell-report.*
|
||||
|
||||
# Release generation artifacts
|
||||
/changelog.md
|
||||
/diff.md
|
||||
|
||||
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
|
||||
# in your Git repository. Update and uncomment the following line accordingly.
|
||||
# <django-project-name>/staticfiles/
|
||||
@@ -231,11 +235,11 @@ source_docs/
|
||||
|
||||
### Golang ###
|
||||
/vendor/
|
||||
server
|
||||
proxy
|
||||
ldap
|
||||
rac
|
||||
radius
|
||||
/server
|
||||
/proxy
|
||||
/ldap
|
||||
/rac
|
||||
/radius
|
||||
|
||||
### Docker ###
|
||||
tests/openid_conformance/exports/*.zip
|
||||
|
||||
@@ -51,6 +51,7 @@ packages/tsconfig @goauthentik/frontend
|
||||
web/ @goauthentik/frontend
|
||||
# Locale
|
||||
/locale/ @goauthentik/backend @goauthentik/frontend
|
||||
/locale/*/dictionaries @goauthentik/frontend @goauthentik/docs
|
||||
web/xliff/ @goauthentik/backend @goauthentik/frontend
|
||||
# Docs
|
||||
website/ @goauthentik/docs
|
||||
|
||||
Generated
+52
-42
@@ -184,7 +184,7 @@ dependencies = [
|
||||
"hyper-util",
|
||||
"metrics",
|
||||
"metrics-exporter-prometheus",
|
||||
"nix 0.31.2",
|
||||
"nix 0.31.3",
|
||||
"pyo3",
|
||||
"pyo3-build-config",
|
||||
"sqlx",
|
||||
@@ -244,7 +244,7 @@ dependencies = [
|
||||
"glob",
|
||||
"ipnet",
|
||||
"json-subscriber",
|
||||
"nix 0.31.2",
|
||||
"nix 0.31.3",
|
||||
"notify",
|
||||
"pin-project-lite",
|
||||
"reqwest",
|
||||
@@ -288,9 +288,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.16.3"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f"
|
||||
checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
|
||||
dependencies = [
|
||||
"aws-lc-fips-sys",
|
||||
"aws-lc-sys",
|
||||
@@ -300,9 +300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.40.0"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7"
|
||||
checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
@@ -485,6 +485,15 @@ dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.2"
|
||||
@@ -1892,9 +1901,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.183"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@@ -2013,9 +2022,9 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "metrics"
|
||||
version = "0.24.5"
|
||||
version = "0.24.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff56c2e7dce6bd462e3b8919986a617027481b1dcc703175b58cf9dd98a2f071"
|
||||
checksum = "89550ee9f79e88fef3119de263694973a8adb26c21d75322164fb8c493039fe2"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
"rapidhash",
|
||||
@@ -2110,9 +2119,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.31.2"
|
||||
version = "0.31.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3"
|
||||
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"cfg-if",
|
||||
@@ -2916,9 +2925,9 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.13.3"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
|
||||
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
@@ -2962,9 +2971,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest-middleware"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "199dda04a536b532d0cc04d7979e39b1c763ea749bf91507017069c00b96056f"
|
||||
checksum = "07bc3f1384cffa4f274dad2d4ddd73aed32fed8f786d96c6be8aa4e5fd3c3b58"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -3193,9 +3202,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "sentry"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93b3e19f45495ddd41d8222a152c48c84f6ba45abe9c69e2527e9cdea29bb5b"
|
||||
checksum = "931a20b0da02350676e3d6d3c9028d58eaa448cf42a866712eec5845a505421e"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"httpdate",
|
||||
@@ -3214,9 +3223,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-backtrace"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc84c325ace9ca2388e510fe7d6672b5d60cd8b3bd0eb4bb4ee8314c323cd686"
|
||||
checksum = "911ee36abf5b7fa335fccd5f54361ba9c16baea5f0c3bb361a687b6c195c21cf"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"regex",
|
||||
@@ -3225,9 +3234,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-contexts"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "896c1ab62dbfe1746fb262bbf72e6feb2fb9dfb2c14709077bf71beb532e44b2"
|
||||
checksum = "9b9d7d469e9e22741c17ca23fb8b42d79861590eb7cf330f3da34fc1e4bc1bc6"
|
||||
dependencies = [
|
||||
"hostname",
|
||||
"libc",
|
||||
@@ -3239,9 +3248,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-core"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f5abf20c42cb1593ec1638976e2647da55f79bccac956444c1707b6cce259a"
|
||||
checksum = "545dc562b6758d646ac19e1407f4ebc26d452111386743e03323464bc48bb2e0"
|
||||
dependencies = [
|
||||
"rand 0.9.4",
|
||||
"sentry-types",
|
||||
@@ -3252,9 +3261,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-debug-images"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b88bbe6a760d5724bb40689827e82e8db1e275947df2c59abe171bfc30bb671"
|
||||
checksum = "660e9def38a573a869a182f7e90f58aaaa460f38b92b31fd1755ec537193bb48"
|
||||
dependencies = [
|
||||
"findshlibs",
|
||||
"sentry-core",
|
||||
@@ -3262,9 +3271,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-panic"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0260dcb52562b6a79ae7702312a26dba94b79fb5baee7301087529e5ca4e872e"
|
||||
checksum = "772d9de150c8ca910c835353c85f434457348fdd21208f9b3da3574202b1dc5d"
|
||||
dependencies = [
|
||||
"sentry-backtrace",
|
||||
"sentry-core",
|
||||
@@ -3272,9 +3281,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-tower"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d669616d5d5279b5712febfc80c343acc3695e499de0d101ed70fceacadf37f2"
|
||||
checksum = "2abea154597936d5df2d39fbe8aac16d584de6b3572c70c39558764d9d2efe15"
|
||||
dependencies = [
|
||||
"sentry-core",
|
||||
"tower-layer",
|
||||
@@ -3283,9 +3292,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-tracing"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1c035f3a0a8671ae1a231c5b457abb68b71acba2bf3054dab2a09a9d4ea487e"
|
||||
checksum = "c51ec9620a4d398dcdf7ee90effbf8d8691cfa24e91978bfa8565cac039d4980"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"sentry-backtrace",
|
||||
@@ -3296,9 +3305,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-types"
|
||||
version = "0.48.1"
|
||||
version = "0.48.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82d8e81058ec155992191f61c7b29bfa7b2cf12012131e7cdc0678020898a7c9"
|
||||
checksum = "041359745a44dd2e14fe21b7510fe7ca8b5beffce6636a0b52e5bc7d5f736887"
|
||||
dependencies = [
|
||||
"debugid",
|
||||
"hex",
|
||||
@@ -3343,9 +3352,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -3390,11 +3399,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.19.0"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05839ce67618e14a09b286535c0d9c94e85ef25469b0e13cb4f844e5593eb19"
|
||||
checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bs58",
|
||||
"chrono",
|
||||
"hex",
|
||||
"serde_core",
|
||||
@@ -4072,9 +4082,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.10"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
|
||||
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"bytes",
|
||||
@@ -4336,9 +4346,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.23.1"
|
||||
version = "1.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
|
||||
checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7"
|
||||
dependencies = [
|
||||
"getrandom 0.4.2",
|
||||
"js-sys",
|
||||
|
||||
+10
-10
@@ -22,7 +22,7 @@ publish = false
|
||||
arc-swap = "= 1.9.1"
|
||||
argh = "= 0.1.19"
|
||||
axum-server = { version = "= 0.8.0", features = ["tls-rustls-no-provider"] }
|
||||
aws-lc-rs = { version = "= 1.16.3", features = ["fips"] }
|
||||
aws-lc-rs = { version = "= 1.17.0", features = ["fips"] }
|
||||
axum = { version = "= 0.8.9", features = ["http2", "macros", "ws"] }
|
||||
clap = { version = "= 4.6.1", features = ["derive", "env"] }
|
||||
client-ip = { version = "0.2.1", features = ["forwarded-header"] }
|
||||
@@ -43,15 +43,15 @@ hyper-unix-socket = "= 0.6.1"
|
||||
hyper-util = "= 0.1.20"
|
||||
ipnet = { version = "= 2.12.0", features = ["serde"] }
|
||||
json-subscriber = "= 0.2.8"
|
||||
metrics = "= 0.24.5"
|
||||
metrics = "= 0.24.6"
|
||||
metrics-exporter-prometheus = { version = "= 0.18.3", default-features = false }
|
||||
nix = { version = "= 0.31.2", features = ["hostname", "signal"] }
|
||||
nix = { version = "= 0.31.3", features = ["hostname", "signal"] }
|
||||
notify = "= 8.2.0"
|
||||
pin-project-lite = "= 0.2.17"
|
||||
pyo3 = "= 0.28.3"
|
||||
pyo3-build-config = "= 0.28.3"
|
||||
regex = "= 1.12.3"
|
||||
reqwest = { version = "= 0.13.3", features = [
|
||||
reqwest = { version = "= 0.13.4", features = [
|
||||
"form",
|
||||
"json",
|
||||
"multipart",
|
||||
@@ -59,7 +59,7 @@ reqwest = { version = "= 0.13.3", features = [
|
||||
"rustls",
|
||||
"stream",
|
||||
] }
|
||||
reqwest-middleware = { version = "= 0.5.1", features = [
|
||||
reqwest-middleware = { version = "= 0.5.2", features = [
|
||||
"form",
|
||||
"json",
|
||||
"multipart",
|
||||
@@ -67,7 +67,7 @@ reqwest-middleware = { version = "= 0.5.1", features = [
|
||||
"rustls",
|
||||
] }
|
||||
rustls = { version = "= 0.23.40", features = ["fips"] }
|
||||
sentry = { version = "= 0.48.1", default-features = false, features = [
|
||||
sentry = { version = "= 0.48.2", default-features = false, features = [
|
||||
"backtrace",
|
||||
"contexts",
|
||||
"debug-images",
|
||||
@@ -78,9 +78,9 @@ sentry = { version = "= 0.48.1", default-features = false, features = [
|
||||
"tracing",
|
||||
] }
|
||||
serde = { version = "= 1.0.228", features = ["derive"] }
|
||||
serde_json = "= 1.0.149"
|
||||
serde_json = "= 1.0.150"
|
||||
serde_repr = "= 0.1.20"
|
||||
serde_with = { version = "= 3.19.0", default-features = false, features = [
|
||||
serde_with = { version = "= 3.20.0", default-features = false, features = [
|
||||
"base64",
|
||||
] }
|
||||
sqlx = { version = "= 0.8.6", default-features = false, features = [
|
||||
@@ -102,7 +102,7 @@ tokio-retry2 = "= 0.9.1"
|
||||
tokio-rustls = "= 0.26.4"
|
||||
tokio-util = { version = "= 0.7.18", features = ["full"] }
|
||||
tower = "= 0.5.3"
|
||||
tower-http = { version = "= 0.6.10", features = ["timeout"] }
|
||||
tower-http = { version = "= 0.6.11", features = ["timeout"] }
|
||||
tracing = "= 0.1.44"
|
||||
tracing-error = "= 0.2.1"
|
||||
tracing-subscriber = { version = "= 0.3.23", features = [
|
||||
@@ -112,7 +112,7 @@ tracing-subscriber = { version = "= 0.3.23", features = [
|
||||
"tracing-log",
|
||||
] }
|
||||
url = "= 2.5.8"
|
||||
uuid = { version = "= 1.23.1", features = ["serde", "v4"] }
|
||||
uuid = { version = "= 1.23.2", features = ["serde", "v4"] }
|
||||
which = "= 8.0.2"
|
||||
|
||||
ak-axum = { package = "authentik-axum", version = "2026.8.0-rc1", path = "./packages/ak-axum" }
|
||||
|
||||
@@ -73,7 +73,7 @@ rust-test: ## Run the Rust tests
|
||||
$(CARGO) nextest run --workspace
|
||||
|
||||
test: ## Run the server tests and produce a coverage report (locally)
|
||||
$(UV) run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik)
|
||||
$(UV) run coverage run manage.py test --keepdb $(or $(filter-out $@ all,$(MAKECMDGOALS)),authentik)
|
||||
$(UV) run coverage combine
|
||||
$(UV) run coverage html
|
||||
$(UV) run coverage report
|
||||
@@ -186,7 +186,7 @@ gen-changelog: ## (Release) generate the changelog based from the commits since
|
||||
git log --pretty=format:"- %s" $(shell git merge-base ${last_version} ${current_commit})...${current_commit} > merged_to_current
|
||||
git log --pretty=format:"- %s" $(shell git merge-base ${last_version} ${current_commit})...${last_version} > merged_to_last
|
||||
grep -Eo 'cherry-pick (#\d+)' merged_to_last | cut -d ' ' -f 2 | sed 's/.*/(&)$$/' > cherry_picked_to_last
|
||||
grep -vf cherry_picked_to_last merged_to_current | sort > changelog.md
|
||||
grep -vf cherry_picked_to_last merged_to_current | grep -vE '^- (ci:|website)' | sort > changelog.md
|
||||
rm merged_to_current
|
||||
rm merged_to_last
|
||||
rm cherry_picked_to_last
|
||||
@@ -201,8 +201,8 @@ gen-diff: ## (Release) generate the changelog diff between the current schema a
|
||||
/local/schema-old.yml \
|
||||
/local/schema.yml
|
||||
rm schema-old.yml
|
||||
$(SED_INPLACE) 's/{/{/g' diff.md
|
||||
$(SED_INPLACE) 's/}/}/g' diff.md
|
||||
$(SED_INPLACE) 's/{/\{/g' diff.md
|
||||
$(SED_INPLACE) 's/}/\}/g' diff.md
|
||||
npx prettier --write diff.md
|
||||
|
||||
gen-client-go: ## Build and install the authentik API for Golang
|
||||
|
||||
@@ -36,6 +36,8 @@ Our [enterprise offering](https://goauthentik.io/pricing) is available for organ
|
||||
|
||||
See the [Developer Documentation](https://docs.goauthentik.io/docs/developer-docs/) for information about setting up local build environments, testing your contributions, and our contribution process.
|
||||
|
||||
When you contribute documentation, either to accompany a code change or as a standalone contribution, please be sure to follow our documentation [Style Guide](website/docs/developer-docs/docs/style-guide.mdx).
|
||||
|
||||
## Security
|
||||
|
||||
Please see [SECURITY.md](SECURITY.md).
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
|
||||
|
||||
| Version | Supported |
|
||||
| --------- | --------- |
|
||||
| 2025.12.x | ✅ |
|
||||
| 2026.2.x | ✅ |
|
||||
| 2025.2.x | ✅ |
|
||||
| 2026.5.x | ✅ |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ entries:
|
||||
slug: "%(uid)s-source"
|
||||
attrs:
|
||||
name: "%(uid)s-source"
|
||||
provider_type: azuread
|
||||
provider_type: entraid
|
||||
consumer_key: "%(uid)s"
|
||||
consumer_secret: "%(uid)s"
|
||||
icon: https://goauthentik.io/img/icon.png
|
||||
|
||||
@@ -323,6 +323,42 @@ class Importer:
|
||||
serializer.instance = model_instance
|
||||
return serializer
|
||||
|
||||
def _save_with_retry(
|
||||
self, serializer: BaseSerializer, entry: BlueprintEntry, raise_errors: bool
|
||||
) -> Model | None:
|
||||
"""Save a serializer, retrying once on IntegrityError by re-fetching the existing instance.
|
||||
|
||||
Returns the saved instance, or None when recovery failed and raise_errors is False.
|
||||
Raises EntryInvalidError / IntegrityError when raise_errors is True and recovery
|
||||
is not possible.
|
||||
"""
|
||||
try:
|
||||
with atomic():
|
||||
return serializer.save()
|
||||
except IntegrityError:
|
||||
self.logger.debug(
|
||||
"Integrity error during save, retrying after re-fetching instance",
|
||||
entry=entry,
|
||||
)
|
||||
# Race condition: another process committed the same object between our
|
||||
# SELECT and INSERT. Re-validate so we pick up the now-existing instance.
|
||||
try:
|
||||
retry_serializer = self._validate_single(entry)
|
||||
except EntryInvalidError as exc:
|
||||
self.logger.warning(f"Entry invalid on retry: {exc}", entry=entry, error=exc)
|
||||
if raise_errors:
|
||||
raise exc
|
||||
return None
|
||||
if not retry_serializer:
|
||||
return None
|
||||
try:
|
||||
return retry_serializer.save()
|
||||
except IntegrityError:
|
||||
self.logger.warning("Integrity error persists on retry", entry=entry)
|
||||
if raise_errors:
|
||||
raise
|
||||
return None
|
||||
|
||||
def _apply_permissions(self, instance: Model, entry: BlueprintEntry):
|
||||
"""Apply object-level permissions for an entry"""
|
||||
for perm in entry.get_permissions(self._import):
|
||||
@@ -393,7 +429,9 @@ class Importer:
|
||||
pk=instance.pk,
|
||||
)
|
||||
else:
|
||||
instance = serializer.save()
|
||||
instance = self._save_with_retry(serializer, entry, raise_errors)
|
||||
if instance is None:
|
||||
return False
|
||||
self.logger.debug("Updated model", model=instance)
|
||||
if "pk" in entry.identifiers:
|
||||
self.__pk_map[entry.identifiers["pk"]] = instance.pk
|
||||
|
||||
@@ -133,6 +133,7 @@ class UserSourceConnectionSerializer(SourceSerializer):
|
||||
"last_updated",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"user": {"read_only": True},
|
||||
"created": {"read_only": True},
|
||||
"last_updated": {"read_only": True},
|
||||
}
|
||||
@@ -173,6 +174,7 @@ class GroupSourceConnectionSerializer(SourceSerializer):
|
||||
"last_updated",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"group": {"read_only": True},
|
||||
"created": {"read_only": True},
|
||||
"last_updated": {"read_only": True},
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
{# Darkreader breaks the site regardless of theme as its not compatible with webcomponents, and we default to a dark theme based on preferred colour-scheme #}
|
||||
{# Darkreader breaks the site regardless of theme as its not compatible with webcomponents, and we default to a dark theme based on preferred color-scheme #}
|
||||
<meta name="darkreader-lock">
|
||||
<title>{% block title %}{% trans title|default:brand.branding_title %}{% endblock %}</title>
|
||||
<link rel="icon" href="{{ brand.branding_favicon_url }}">
|
||||
|
||||
@@ -7,7 +7,7 @@ from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_sche
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
from rest_framework.fields import ChoiceField
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.relations import PrimaryKeyRelatedField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
@@ -118,8 +118,7 @@ class AgentConnectorViewSet(
|
||||
methods=["POST"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentEnrollmentAuth],
|
||||
# Permissions are handled via AgentEnrollmentAuth
|
||||
permission_classes=[AllowAny],
|
||||
permission_classes=[IsAuthenticated],
|
||||
)
|
||||
def enroll(self, request: Request):
|
||||
token: EnrollmentToken = request.auth
|
||||
@@ -154,8 +153,7 @@ class AgentConnectorViewSet(
|
||||
methods=["GET"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentAuth],
|
||||
# Permissions are handled via AgentAuth
|
||||
permission_classes=[AllowAny],
|
||||
permission_classes=[IsAuthenticated],
|
||||
)
|
||||
def agent_config(self, request: Request):
|
||||
token: DeviceToken = request.auth
|
||||
@@ -174,8 +172,7 @@ class AgentConnectorViewSet(
|
||||
methods=["POST"],
|
||||
detail=False,
|
||||
authentication_classes=[AgentAuth],
|
||||
# Permissions are handled via AgentAuth
|
||||
permission_classes=[AllowAny],
|
||||
permission_classes=[IsAuthenticated],
|
||||
)
|
||||
def check_in(self, request: Request):
|
||||
token: DeviceToken = request.auth
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any
|
||||
|
||||
from django.db.models import Model
|
||||
from django.db.models import Model, Q
|
||||
from django.http import HttpRequest
|
||||
from django.utils.timezone import now
|
||||
from drf_spectacular.extensions import OpenApiAuthenticationExtension
|
||||
@@ -101,7 +101,22 @@ class DeviceAuthFedAuthentication(BaseAuthentication):
|
||||
if not raw_token:
|
||||
LOGGER.warning("Missing token")
|
||||
return None
|
||||
device = Device.objects.filter(name=request.query_params.get("device")).first()
|
||||
device = (
|
||||
Device.objects.filter(
|
||||
Q(
|
||||
name=request.query_params.get("device"),
|
||||
)
|
||||
| Q(
|
||||
**{
|
||||
"deviceconnection__devicefactsnapshot__"
|
||||
"data__vendor__goauthentik.io/platform__"
|
||||
"ssh_host_keys__contains": request.query_params.get("device"),
|
||||
}
|
||||
)
|
||||
)
|
||||
.distinct()
|
||||
.first()
|
||||
)
|
||||
if not device:
|
||||
LOGGER.warning("Couldn't find device")
|
||||
return None
|
||||
|
||||
@@ -124,6 +124,14 @@ class TestAgentAPI(APITestCase):
|
||||
)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
@reconcile_app("authentik_crypto")
|
||||
def test_config_none(self):
|
||||
response = self.client.get(
|
||||
reverse("authentik_api:agentconnector-agent-config"),
|
||||
HTTP_AUTHORIZATION="Bearer foo",
|
||||
)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_check_in(self):
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:agentconnector-check-in"),
|
||||
|
||||
@@ -19,6 +19,7 @@ from authentik.providers.oauth2.models import AccessToken, OAuth2Provider
|
||||
class TestConnectorAuthFed(APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.ssh_host_key = generate_id()
|
||||
self.connector = AgentConnector.objects.create(name=generate_id())
|
||||
self.token = EnrollmentToken.objects.create(name=generate_id(), connector=self.connector)
|
||||
self.device = Device.objects.create(
|
||||
@@ -29,6 +30,19 @@ class TestConnectorAuthFed(APITestCase):
|
||||
device=self.device,
|
||||
connector=self.connector,
|
||||
)
|
||||
self.connection.create_snapshot(
|
||||
data={
|
||||
"vendor": {
|
||||
"goauthentik.io/platform": {
|
||||
"ssh_host_keys": [
|
||||
"foo",
|
||||
self.ssh_host_key,
|
||||
"baz",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.user = create_test_user()
|
||||
self.provider = OAuth2Provider.objects.create(
|
||||
name=generate_id(), signing_key=create_test_cert()
|
||||
@@ -40,13 +54,34 @@ class TestConnectorAuthFed(APITestCase):
|
||||
self.connector.jwt_federation_providers.add(self.provider)
|
||||
|
||||
@reconcile_app("authentik_crypto")
|
||||
def test_auth_fed(self):
|
||||
def test_auth_fed_no_access(self):
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:agentconnector-auth-fed") + f"?device={self.device.name}",
|
||||
HTTP_AUTHORIZATION=f"Bearer {self.raw_token}",
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
@reconcile_app("authentik_crypto")
|
||||
def test_auth_fed_policy_group_by_host_key(self):
|
||||
device_group = DeviceAccessGroup.objects.create(name=generate_id())
|
||||
self.device.access_group = device_group
|
||||
self.device.save()
|
||||
|
||||
group = Group.objects.create(name=generate_id())
|
||||
group.users.add(self.user)
|
||||
|
||||
PolicyBinding.objects.create(target=device_group, group=group, order=0)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:agentconnector-auth-fed") + f"?device={self.ssh_host_key}",
|
||||
HTTP_AUTHORIZATION=f"Bearer {self.raw_token}",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
res = loads(response.content)
|
||||
token = decode(res["token"], options={"verify_signature": False})
|
||||
self.assertEqual(token["iss"], "goauthentik.io/platform")
|
||||
self.assertEqual(token["aud"], str(self.device.pk))
|
||||
|
||||
@reconcile_app("authentik_crypto")
|
||||
def test_auth_fed_policy_group(self):
|
||||
device_group = DeviceAccessGroup.objects.create(name=generate_id())
|
||||
|
||||
@@ -68,13 +68,16 @@ class SCIMOAuthAuth:
|
||||
return conn
|
||||
token = self.retrieve_token(conn)
|
||||
access_token = token["access_token"]
|
||||
refresh_token = token.get("refresh_token")
|
||||
if not refresh_token and conn:
|
||||
refresh_token = conn.refresh_token
|
||||
expires_in = int(token.get("expires_in", 0))
|
||||
token, _ = UserOAuthSourceConnection.objects.update_or_create(
|
||||
source=self.provider.auth_oauth,
|
||||
user=self.user,
|
||||
defaults={
|
||||
"access_token": access_token,
|
||||
"refresh_token": token.get("refresh_token"),
|
||||
"refresh_token": refresh_token,
|
||||
"expires": now() + timedelta(seconds=expires_in),
|
||||
# When using `update_or_create`, `last_updated` is not updated
|
||||
"last_updated": now(),
|
||||
|
||||
@@ -104,6 +104,7 @@ class TestSCIMOAuthToken(APITestCase):
|
||||
source=self.source,
|
||||
user=self.provider.auth_oauth_user,
|
||||
).first()
|
||||
self.assertEqual(conn.refresh_token, refresh_token)
|
||||
self.assertIsNotNone(conn)
|
||||
self.assertTrue(conn.is_valid)
|
||||
auth = (
|
||||
|
||||
@@ -65,6 +65,7 @@ class SCIMRedirectCallback(SCIMOAuthViewMixin, OAuthCallback):
|
||||
"access_token": self.token.get("access_token"),
|
||||
"refresh_token": self.token.get("refresh_token"),
|
||||
"expires": now() + timedelta(seconds=expires_in),
|
||||
"last_updated": now(),
|
||||
},
|
||||
)
|
||||
return redirect("authentik_core:if-admin")
|
||||
|
||||
@@ -14,6 +14,7 @@ from cryptography.x509 import (
|
||||
load_pem_x509_certificate,
|
||||
)
|
||||
from cryptography.x509.verification import PolicyBuilder, Store, VerificationError
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
@@ -138,9 +139,9 @@ class MTLSStageView(ChallengeStageView):
|
||||
authorities_cert = [x.certificate for x in authorities]
|
||||
for _cert in certs:
|
||||
try:
|
||||
PolicyBuilder().store(Store(authorities_cert)).build_client_verifier().verify(
|
||||
_cert, []
|
||||
)
|
||||
PolicyBuilder().store(Store(authorities_cert)).time(
|
||||
now()
|
||||
).build_client_verifier().verify(_cert, [])
|
||||
return _cert
|
||||
except (
|
||||
InvalidSignature,
|
||||
|
||||
@@ -3,6 +3,7 @@ from unittest.mock import MagicMock, patch
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
from django.urls import reverse
|
||||
from freezegun import freeze_time
|
||||
|
||||
from authentik.core.models import User
|
||||
from authentik.core.tests.utils import (
|
||||
@@ -28,6 +29,7 @@ from authentik.outposts.models import Outpost, OutpostType
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
|
||||
|
||||
@freeze_time("2026-05-10 12:38:46")
|
||||
class MTLSStageTests(FlowTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -16,7 +16,7 @@ from authentik.core.sources.flow_manager import (
|
||||
)
|
||||
from authentik.core.types import UILoginButton
|
||||
from authentik.enterprise.stages.source.models import SourceStage
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse
|
||||
from authentik.flows.challenge import Challenge, ChallengeResponse, HttpChallengeResponse
|
||||
from authentik.flows.models import FlowToken, in_memory_stage
|
||||
from authentik.flows.planner import PLAN_CONTEXT_IS_REDIRECTED, PLAN_CONTEXT_IS_RESTORED
|
||||
from authentik.flows.stage import ChallengeStageView, StageView
|
||||
@@ -84,7 +84,8 @@ class SourceStageView(ChallengeStageView):
|
||||
return token
|
||||
|
||||
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
|
||||
return self.executor.stage_ok()
|
||||
# Completion happens via dispatch(), not here.
|
||||
return HttpChallengeResponse(self._get_challenge())
|
||||
|
||||
|
||||
class SourceStageFinal(StageView):
|
||||
|
||||
@@ -7,13 +7,6 @@ from authentik.lib.config import CONFIG, ENV_PREFIX
|
||||
from authentik.lib.utils.time import fqdn_rand
|
||||
from authentik.tasks.schedules.common import ScheduleSpec
|
||||
|
||||
# TODO: Deprecated metric - remove in 2024.2 or later
|
||||
GAUGE_TASKS = Gauge(
|
||||
"authentik_system_tasks",
|
||||
"System tasks and their status",
|
||||
["tenant", "task_name", "task_uid", "status"],
|
||||
)
|
||||
|
||||
SYSTEM_TASK_TIME = Histogram(
|
||||
"authentik_system_tasks_time_seconds",
|
||||
"Runtime of system tasks",
|
||||
|
||||
@@ -49,15 +49,6 @@ class LogEventSerializer(PassiveSerializer):
|
||||
event = CharField()
|
||||
attributes = DictField()
|
||||
|
||||
# TODO(2024.6?): This is a migration helper to return a correct API response for logs that
|
||||
# have been saved in an older format (mostly just list[str] with just the messages)
|
||||
def to_representation(self, instance):
|
||||
if isinstance(instance, str):
|
||||
instance = LogEvent(instance, "", "")
|
||||
elif isinstance(instance, list):
|
||||
instance = [LogEvent(x, "", "") for x in instance]
|
||||
return super().to_representation(instance)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def capture_logs(log_default_output=True) -> Generator[list[LogEvent]]:
|
||||
|
||||
@@ -17,7 +17,7 @@ class Migration(migrations.Migration):
|
||||
name="webhook_ca",
|
||||
field=models.ForeignKey(
|
||||
default=None,
|
||||
help_text="When set, the selected ceritifcate is used to validate the certificate of the webhook server.",
|
||||
help_text="When set, the selected certificate is used to validate the certificate of the webhook server.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_DEFAULT,
|
||||
to="authentik_crypto.certificatekeypair",
|
||||
|
||||
@@ -258,6 +258,7 @@ class Event(SerializerModel, ExpiringModel):
|
||||
action=EventAction.CONFIGURATION_WARNING,
|
||||
context__deprecation=identifier,
|
||||
)
|
||||
cause = str(cause)
|
||||
if cause:
|
||||
query &= Q(context__cause=cause)
|
||||
if Event.objects.filter(query).exists():
|
||||
@@ -360,7 +361,7 @@ class NotificationTransport(TasksModel, SerializerModel):
|
||||
default=None,
|
||||
on_delete=models.SET_DEFAULT,
|
||||
help_text=_(
|
||||
"When set, the selected ceritifcate is used to "
|
||||
"When set, the selected certificate is used to "
|
||||
"validate the certificate of the webhook server."
|
||||
),
|
||||
)
|
||||
|
||||
@@ -225,3 +225,14 @@ class TestEvents(TestCase):
|
||||
|
||||
new_count = Event.objects.filter(action=EventAction.PASSWORD_SET, user__pk=user.pk).count()
|
||||
self.assertEqual(new_count, old_count + 1)
|
||||
|
||||
def test_log_deprecation(self):
|
||||
"""Test Event.log_deprecation"""
|
||||
Event.log_deprecation(self.__module__, "Test deprecation")
|
||||
Event.log_deprecation(self.__module__, "Test deprecation")
|
||||
Event.log_deprecation(self.__module__, "Test deprecation")
|
||||
Event.log_deprecation(self.__module__, "Test deprecation", cause=create_test_user())
|
||||
logs = Event.objects.filter(
|
||||
action=EventAction.CONFIGURATION_WARNING, context__deprecation=self.__module__
|
||||
)
|
||||
self.assertEqual(logs.count(), 2)
|
||||
|
||||
@@ -128,6 +128,7 @@ class SessionEndChallenge(WithUserInfoChallenge):
|
||||
application_launch_url = CharField(required=False)
|
||||
|
||||
invalidation_flow_url = CharField(required=False)
|
||||
overview_url = CharField(required=False)
|
||||
brand_name = CharField(required=True)
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from sentry_sdk import start_span
|
||||
from structlog.stdlib import BoundLogger, get_logger
|
||||
|
||||
from authentik.common.oauth.constants import PLAN_CONTEXT_POST_LOGOUT_REDIRECT_URI
|
||||
from authentik.core.models import Application, User
|
||||
from authentik.core.models import Application, User, UserTypes
|
||||
from authentik.flows.challenge import (
|
||||
AccessDeniedChallenge,
|
||||
Challenge,
|
||||
@@ -331,6 +331,10 @@ class SessionEndStage(ChallengeStageView):
|
||||
"component": "ak-stage-session-end",
|
||||
"brand_name": self.request.brand.branding_title,
|
||||
}
|
||||
if self.get_pending_user().type == UserTypes.INTERNAL:
|
||||
data["overview_url"] = self.request.build_absolute_uri(
|
||||
reverse("authentik_core:root-redirect")
|
||||
)
|
||||
if application:
|
||||
data["application_name"] = application.name
|
||||
data["application_launch_url"] = application.get_launch_url(self.get_pending_user())
|
||||
|
||||
@@ -196,7 +196,7 @@ class FlowExecutorView(APIView):
|
||||
return self.handle_invalid_flow(exc)
|
||||
except EmptyFlowException as exc:
|
||||
self._logger.warning("f(exec): Flow is empty", exc=exc)
|
||||
# To match behaviour with loading an empty flow plan from cache,
|
||||
# To match behavior with loading an empty flow plan from cache,
|
||||
# we don't show an error message here, but rather call _flow_done()
|
||||
return self._flow_done()
|
||||
# We don't save the Plan after getting the next stage
|
||||
|
||||
@@ -59,7 +59,7 @@ def avatar_mode_gravatar(user: User, mode: str) -> str | None:
|
||||
|
||||
|
||||
def generate_colors(text: str) -> tuple[str, str]:
|
||||
"""Generate colours based on `text`"""
|
||||
"""Generate colors based on `text`"""
|
||||
color = (
|
||||
int(md5(text.lower().encode("utf-8"), usedforsecurity=False).hexdigest(), 16) % 0xFFFFFF
|
||||
) # nosec
|
||||
|
||||
@@ -276,7 +276,7 @@ class ConfigLoader:
|
||||
try:
|
||||
return int(value)
|
||||
except (ValueError, TypeError) as exc:
|
||||
if value is None or (isinstance(value, str) and value.lower() == "null"):
|
||||
if value is None or (isinstance(value, str) and value.lower() in ("", "null", "none")):
|
||||
return None
|
||||
self.log("warning", "Failed to parse config as int", path=path, exc=str(exc))
|
||||
return default
|
||||
|
||||
@@ -22,6 +22,7 @@ postgresql:
|
||||
port: 5432
|
||||
password: "env://POSTGRES_PASSWORD"
|
||||
sslmode: disable
|
||||
conn_max_age: 0
|
||||
conn_health_checks: false
|
||||
use_pool: False
|
||||
test:
|
||||
|
||||
@@ -315,7 +315,7 @@ class TestConfig(TestCase):
|
||||
{
|
||||
"default": {
|
||||
"DISABLE_SERVER_SIDE_CURSORS": True,
|
||||
"CONN_MAX_AGE": None,
|
||||
"CONN_MAX_AGE": 0,
|
||||
"CONN_HEALTH_CHECKS": False,
|
||||
"ENGINE": "psqlextra.backend",
|
||||
"HOST": "foo",
|
||||
|
||||
@@ -23,6 +23,7 @@ from authentik.lib.utils.time import timedelta_from_string, timedelta_string_val
|
||||
from authentik.outposts.api.service_connections import ServiceConnectionSerializer
|
||||
from authentik.outposts.apps import MANAGED_OUTPOST, MANAGED_OUTPOST_NAME
|
||||
from authentik.outposts.models import (
|
||||
OUR_VERSION,
|
||||
Outpost,
|
||||
OutpostConfig,
|
||||
OutpostType,
|
||||
@@ -188,7 +189,7 @@ class OutpostViewSet(UsedByMixin, ModelViewSet):
|
||||
"uid": state.uid,
|
||||
"last_seen": state.last_seen,
|
||||
"version": state.version,
|
||||
"version_should": state.version_should,
|
||||
"version_should": OUR_VERSION,
|
||||
"version_outdated": state.version_outdated,
|
||||
"build_hash": state.build_hash,
|
||||
"golang_version": state.golang_version,
|
||||
|
||||
@@ -13,7 +13,7 @@ from django.db import IntegrityError, models, transaction
|
||||
from django.db.models.base import Model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from model_utils.managers import InheritanceManager
|
||||
from packaging.version import Version, parse
|
||||
from packaging.version import parse
|
||||
from rest_framework.serializers import Serializer
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
@@ -464,7 +464,6 @@ class OutpostState:
|
||||
uid: str
|
||||
last_seen: datetime | None = field(default=None)
|
||||
version: str | None = field(default=None)
|
||||
version_should: Version = field(default=OUR_VERSION)
|
||||
build_hash: str = field(default="")
|
||||
golang_version: str = field(default="")
|
||||
openssl_enabled: bool = field(default=False)
|
||||
|
||||
@@ -91,7 +91,7 @@ class LDAPOutpostConfigSerializer(ModelSerializer):
|
||||
unbind_flow_slug = SerializerMethodField()
|
||||
|
||||
def get_application_slug(self, instance: LDAPProvider) -> str:
|
||||
"""Prioritise backchannel slug over direct application slug"""
|
||||
"""Prioritize backchannel slug over direct application slug"""
|
||||
if instance.backchannel_application:
|
||||
return instance.backchannel_application.slug
|
||||
return instance.application.slug
|
||||
|
||||
@@ -88,6 +88,12 @@ class GrantType(models.TextChoices):
|
||||
DEVICE_CODE = GRANT_TYPE_DEVICE_CODE
|
||||
|
||||
|
||||
# Fallback for decoding previous sessions from 2026.2 to 2026.5
|
||||
# https://github.com/goauthentik/authentik/issues/22588
|
||||
# TODO: Remove after 2026.8
|
||||
GrantTypes = GrantType
|
||||
|
||||
|
||||
class ResponseMode(models.TextChoices):
|
||||
"""https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#OAuth.Post"""
|
||||
|
||||
|
||||
@@ -84,8 +84,7 @@ class EndSessionView(PolicyAccessView):
|
||||
"id_token_hint_decode_failed"
|
||||
) from None
|
||||
|
||||
# Validate post_logout_redirect_uri against registered URIs
|
||||
if request_redirect_uri:
|
||||
if request_redirect_uri and self.provider.post_logout_redirect_uris:
|
||||
# OIDC Certification: id_token_hint required with post_logout_redirect_uri
|
||||
if not id_token_hint:
|
||||
raise TokenError("invalid_request").with_cause("id_token_hint_missing")
|
||||
|
||||
@@ -53,6 +53,7 @@ class ServiceProviderMetadata:
|
||||
)
|
||||
provider.sp_binding = self.acs_binding
|
||||
provider.acs_url = self.acs_location
|
||||
provider.audience = self.entity_id
|
||||
provider.default_name_id_policy = self.name_id_policy
|
||||
# Single Logout Service
|
||||
if self.sls_location:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" ID="_1fac8a70c9d2766aed298165ed66dcae" Version="2.0" IssueInstant="2026-05-19T01:01:53.461Z">
|
||||
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://sp.example.invalid/saml</saml2:Issuer>
|
||||
</saml2p:AuthnRequest>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<saml2p:LogoutRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" ID="_logout" Version="2.0" IssueInstant="2026-05-19T01:01:53.461Z">
|
||||
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://sp.example.invalid/saml</saml2:Issuer>
|
||||
</saml2p:LogoutRequest>
|
||||
@@ -103,7 +103,7 @@ class TestServiceProviderMetadataParser(TestCase):
|
||||
provider.verification_kp.certificate_data, load_fixture("fixtures/cert.pem")
|
||||
)
|
||||
self.assertIsNotNone(provider.signing_kp)
|
||||
self.assertEqual(provider.audience, "")
|
||||
self.assertEqual(provider.audience, "http://localhost:8080/apps/user_saml/saml/metadata")
|
||||
|
||||
def test_with_signing_cert_invalid_signature(self):
|
||||
"""Test Metadata with signing cert (invalid signature)"""
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Test unified SAML endpoint helpers."""
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from authentik.lib.tests.utils import load_fixture
|
||||
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode
|
||||
from authentik.providers.saml.views.unified import (
|
||||
SAML_MESSAGE_TYPE_AUTHN_REQUEST,
|
||||
SAML_MESSAGE_TYPE_LOGOUT_REQUEST,
|
||||
detect_saml_message_type,
|
||||
)
|
||||
|
||||
|
||||
class TestDetectSAMLMessageType(SimpleTestCase):
|
||||
"""Test SAML request type detection."""
|
||||
|
||||
def test_redirect_authn_request_with_xml_declaration(self):
|
||||
"""Detect redirect-binding AuthnRequest with an XML declaration."""
|
||||
request = deflate_and_base64_encode(
|
||||
load_fixture("fixtures/authn_request_xml_declaration.xml")
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
detect_saml_message_type(request, is_post_binding=False),
|
||||
SAML_MESSAGE_TYPE_AUTHN_REQUEST,
|
||||
)
|
||||
|
||||
def test_redirect_logout_request_with_xml_declaration(self):
|
||||
"""Detect redirect-binding LogoutRequest with an XML declaration."""
|
||||
request = deflate_and_base64_encode(
|
||||
load_fixture("fixtures/logout_request_xml_declaration.xml")
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
detect_saml_message_type(request, is_post_binding=False),
|
||||
SAML_MESSAGE_TYPE_LOGOUT_REQUEST,
|
||||
)
|
||||
@@ -127,7 +127,7 @@ class SAMLFlowFinalView(ChallengeStageView):
|
||||
"Redirect binding for Service Provider binding is deprecated "
|
||||
"and will be removed in a future version. Use Post binding instead."
|
||||
),
|
||||
cause=provider,
|
||||
cause=provider.name,
|
||||
)
|
||||
url_args = {
|
||||
REQUEST_KEY_SAML_RESPONSE: deflate_and_base64_encode(response),
|
||||
|
||||
@@ -42,6 +42,9 @@ def detect_saml_message_type(saml_request: str, is_post_binding: bool) -> str |
|
||||
else:
|
||||
decoded_xml = decode_base64_and_inflate(saml_request)
|
||||
|
||||
if isinstance(decoded_xml, str):
|
||||
decoded_xml = decoded_xml.encode()
|
||||
|
||||
root = fromstring(decoded_xml)
|
||||
if len(root.xpath("//samlp:AuthnRequest", namespaces=NS_MAP)):
|
||||
return SAML_MESSAGE_TYPE_AUTHN_REQUEST
|
||||
|
||||
@@ -22,7 +22,7 @@ class ObjectPermissions(DjangoObjectPermissions):
|
||||
lookup = getattr(view, "lookup_url_kwarg", None) or getattr(view, "lookup_field", None)
|
||||
if lookup and lookup in view.kwargs:
|
||||
return True
|
||||
# Legacy behaviour:
|
||||
# Legacy behavior:
|
||||
# Allow creation of objects even without explicit permission
|
||||
queryset = self._queryset(view)
|
||||
required_perms = self.get_required_permissions(request.method, queryset.model)
|
||||
|
||||
@@ -19,6 +19,18 @@ def pytest_sessionstart(*_, **__):
|
||||
"""Clear the console ahead of the pytest output starting"""
|
||||
if not IS_CI:
|
||||
print("\x1b[2J\x1b[H")
|
||||
# Pre-warm cryptography's PyO3 PyDateTime type cache with the real
|
||||
# datetime class. If the first extraction happens under @freeze_time
|
||||
# (e.g. in MTLSStageTests), PyO3 caches freezegun's FakeDatetime,
|
||||
# which breaks every later test that passes a real datetime into
|
||||
# cryptography ("TypeError: 'datetime' object is not an instance
|
||||
# of 'FakeDatetime'"). The discard is intentional — only side
|
||||
# effect needed is the type-cache initialization.
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from cryptography.x509.verification import PolicyBuilder
|
||||
|
||||
PolicyBuilder().time(datetime.now(tz=UTC))
|
||||
yield
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from argparse import ArgumentParser
|
||||
from unittest import TestCase
|
||||
from unittest.mock import patch
|
||||
|
||||
import freezegun
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
@@ -91,6 +92,8 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
|
||||
|
||||
self.task_broker = use_test_broker()
|
||||
|
||||
freezegun.configure(extend_ignore_list=["cryptography"])
|
||||
|
||||
# Send startup signals
|
||||
pre_startup.send(sender=self, mode="test")
|
||||
startup.send(sender=self, mode="test")
|
||||
|
||||
@@ -10,7 +10,6 @@ LOGGER = get_logger()
|
||||
|
||||
AUTHENTIK_SOURCES_OAUTH_TYPES = [
|
||||
"authentik.sources.oauth.types.apple",
|
||||
"authentik.sources.oauth.types.azure_ad",
|
||||
"authentik.sources.oauth.types.discord",
|
||||
"authentik.sources.oauth.types.entra_id",
|
||||
"authentik.sources.oauth.types.facebook",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.2.14 on 2026-05-09 19:01
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_azuread_to_entraid(apps, schema_editor):
|
||||
OAuthSource = apps.get_model("authentik_sources_oauth", "OAuthSource")
|
||||
|
||||
db_alias = schema_editor.connection.alias
|
||||
OAuthSource.objects.using(db_alias).filter(provider_type="azuread").update(
|
||||
provider_type="entraid"
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_sources_oauth", "0013_useroauthsourceconnection_refresh_token"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_azuread_to_entraid, migrations.RunPython.noop),
|
||||
]
|
||||
@@ -251,17 +251,6 @@ class GoogleOAuthSource(CreatableType, OAuthSource):
|
||||
verbose_name_plural = _("Google OAuth Sources")
|
||||
|
||||
|
||||
class AzureADOAuthSource(CreatableType, OAuthSource):
|
||||
"""(Deprecated) Social Login using Azure AD."""
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
verbose_name = _("Azure AD OAuth Source")
|
||||
verbose_name_plural = _("Azure AD OAuth Sources")
|
||||
|
||||
|
||||
# TODO: When removing this, add a migration for OAuthSource that sets
|
||||
# provider_type to `entraid` if it is currently `azuread`
|
||||
class EntraIDOAuthSource(CreatableType, OAuthSource):
|
||||
"""Social Login using Entra ID."""
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
"""AzureAD OAuth2 Views"""
|
||||
|
||||
from authentik.sources.oauth.types.entra_id import EntraIDType
|
||||
from authentik.sources.oauth.types.registry import registry
|
||||
|
||||
# TODO: When removing this, add a migration for OAuthSource that sets
|
||||
# provider_type to `entraid` if it is currently `azuread`
|
||||
|
||||
|
||||
@registry.register()
|
||||
class AzureADType(EntraIDType):
|
||||
"""Azure AD Type definition"""
|
||||
|
||||
verbose_name = "Azure AD"
|
||||
name = "azuread"
|
||||
|
||||
urls_customizable = True
|
||||
@@ -76,7 +76,7 @@ class GitHubType(SourceType):
|
||||
chosen_email = info.get("email")
|
||||
if not chosen_email:
|
||||
# The GitHub Userprofile API only returns an email address if the profile
|
||||
# has a public email address set (despite us asking for user:email, this behaviour
|
||||
# has a public email address set (despite us asking for user:email, this behavior
|
||||
# doesn't change.). So we fetch all the user's email addresses
|
||||
emails = client.get_github_emails(token)
|
||||
for email in emails:
|
||||
|
||||
@@ -67,7 +67,7 @@ class OpenIDConnectOAuth2Callback(OAuthCallback):
|
||||
client_class = OpenIDConnectClient
|
||||
|
||||
def get_user_id(self, info: dict[str, str]) -> str:
|
||||
return info.get("sub", None)
|
||||
return str(info.get("sub") or info.get("id"))
|
||||
|
||||
|
||||
@registry.register()
|
||||
|
||||
@@ -143,9 +143,21 @@ class ResponseProcessor:
|
||||
if datetime.fromisoformat(on_or_after).replace(tzinfo=UTC) < _now:
|
||||
raise SAMLException("Assertion is not valid yet or expired.")
|
||||
|
||||
def _verify_signature(self, signature_node: _Element):
|
||||
"""Verify a single signature node"""
|
||||
xmlsec.tree.add_ids(self._root, ["ID"])
|
||||
def _verify_signature(self, signature_node: _Element, target: _Element):
|
||||
"""Verify a single signature node against the given target element."""
|
||||
target_id = target.attrib.get("ID")
|
||||
if not target_id:
|
||||
raise InvalidSignature("Signed element is missing an ID attribute.")
|
||||
refs = signature_node.xpath("./ds:SignedInfo/ds:Reference", namespaces=NS_MAP)
|
||||
if len(refs) != 1:
|
||||
raise InvalidSignature("Signature must contain exactly one Reference.")
|
||||
ref_uri = refs[0].get("URI", "")
|
||||
if ref_uri not in ("", f"#{target_id}"):
|
||||
raise InvalidSignature(
|
||||
"Signature Reference URI does not match the signed element's ID."
|
||||
)
|
||||
|
||||
xmlsec.tree.add_ids(target, ["ID"])
|
||||
|
||||
ctx = xmlsec.SignatureContext()
|
||||
key = xmlsec.Key.from_memory(
|
||||
@@ -168,24 +180,22 @@ class ResponseProcessor:
|
||||
signature_nodes = self._root.xpath("/samlp:Response/ds:Signature", namespaces=NS_MAP)
|
||||
|
||||
if len(signature_nodes) != 1:
|
||||
raise InvalidSignature("No Signature exists in the Response element.")
|
||||
raise InvalidSignature("Expected exactly one Signature in the Response element.")
|
||||
|
||||
self._verify_signature(signature_nodes[0])
|
||||
self._verify_signature(signature_nodes[0], self._root)
|
||||
|
||||
def _verify_assertion_signature(self):
|
||||
"""Verify SAML Assertion's Signature (after decryption)"""
|
||||
signature_nodes = self._root.xpath(
|
||||
"/samlp:Response/saml:Assertion/ds:Signature", namespaces=NS_MAP
|
||||
)
|
||||
|
||||
if len(signature_nodes) != 1:
|
||||
raise InvalidSignature("No Signature exists in the Assertion element.")
|
||||
raise InvalidSignature("Expected exactly one signed Assertion in the Response.")
|
||||
signature_node = signature_nodes[0]
|
||||
assertion = signature_node.getparent()
|
||||
|
||||
self._verify_signature(signature_nodes[0])
|
||||
parent = signature_nodes[0].getparent()
|
||||
if parent is None or parent.tag != f"{{{NS_SAML_ASSERTION}}}Assertion":
|
||||
raise InvalidSignature("No Signature exists in the Assertion element.")
|
||||
self._assertion = parent
|
||||
self._verify_signature(signature_node, assertion)
|
||||
self._assertion = assertion
|
||||
|
||||
def _verify_request_id(self):
|
||||
if self._source.allow_idp_initiated:
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_resp_assert_uri_empty" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"><saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion ID="_assert" Version="2.0" IssueInstant="2014-07-17T01:01:48Z"><saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
||||
<SignedInfo>
|
||||
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<Reference URI="">
|
||||
<Transforms>
|
||||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
</Transforms>
|
||||
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<DigestValue>6AZlgEwsPEWwPPioj5HiNRStaPAm70zIRSBGnYaRc+E=</DigestValue>
|
||||
</Reference>
|
||||
</SignedInfo>
|
||||
<SignatureValue>fei+JUaTHlQuy6/icjyZKUh5kx9qvL5xEqUfwOa1kiLtlfCbMCcEFHMEjePb1uPW
|
||||
fAePa/v9mIl8pV7TrALI1xicdwRPvvM6xgiWe5hQDU+MKd88bHuU/O/0DUktku+e
|
||||
ANR4kYQUAgkmmMCSPSruD3zIgVTAI8AMEpTtDNuHr8C12phsDkqaRQ1OP/ptC//2
|
||||
s6eeJ0DizMWkv/UHrqN8PSoTSgIl30Ffq30t/9TY644lBjgcQZD4h0uvpaRo/M0/
|
||||
yxcgfP6U3ec9ucePFJKprNXvkmNSh/DGbA0BPx1zoB7xf1nhyIYZI76GqC1NP0rh
|
||||
YQ1BinW++XE19PvY66MnIA==</SignatureValue>
|
||||
<KeyInfo>
|
||||
<X509Data>
|
||||
<X509Certificate>MIIC0jCCAbqgAwIBAgIUXHr2/LJAqtsJ4CcXkFjMwJo8HmQwDQYJKoZIhvcNAQEL
|
||||
BQAwIzEhMB8GA1UEAwwYVVJJLWVtcHR5IGFzc2VydGlvbiB0ZXN0MB4XDTE0MDEw
|
||||
MTAwMDAwMFoXDTMwMDEwMTAwMDAwMFowIzEhMB8GA1UEAwwYVVJJLWVtcHR5IGFz
|
||||
c2VydGlvbiB0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArzIB
|
||||
E4WYhfFNJk2VcvxTX9+cdyJ+v+GCAU4BxSJ1/97BPf3UN4yob23qohnnnMlGAO2x
|
||||
QBK2VBQKjNZo3qwy2t5xhsa0YLjjWGxAEL1s5K8cQlkYwkciTy+RFpMXmM80kk8p
|
||||
ZdZFgrjf5ltincH4QuhJcN3/fsEibHQibymWeb/0I3Mba6Uh+gssMN82NYETl677
|
||||
I+5HV4wgJWMh1vaZFbid+YFBeWWJoIAIdbTQEAwIJriTA43lgbcK0Lo9A8/RCH1O
|
||||
RVsQSkpA3kfs9yJ9AvKglBIThapR1iRgtVsC9LdiauHmiNU+8POSHXWByXaWOK0o
|
||||
Izfg/lI+xKSWJerhUwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA+/3kRE6jYFfgy
|
||||
vHZdOX2cFOA5Y0N/RZmdt34tsfCiqP2vHtfQUje8gQAhjmV6dFk4wptPF1FsP601
|
||||
bMp+9LsRsb4y6pxy5m7xKVK9P/EI33N2zZZL9tlJ7CPIA81DPi53lYOvX54UIi2I
|
||||
GpF6QyYMX2HTs/KVxo4gYnOnkyqPw6QrKaWpJLQndQd1rTn4/ybWW/9XU46RYf7/
|
||||
7Z8H8t4n4lhPYm5WGer4eG+k+F3R04yhwSm3Wi91gkQwQdGPgFSPe1z8TusDw/Q/
|
||||
1ax1a/mNoN9NCcZgg3L0xZgbtDnzBr/Gd/MWBQdDgRM7DpcWaVVcXq5GRLLeAvwM
|
||||
uF73araE
|
||||
</X509Certificate>
|
||||
</X509Data>
|
||||
</KeyInfo>
|
||||
</Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">test_user</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z"><saml:AudienceRestriction><saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionIndex="_session"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion></samlp:Response>
|
||||
@@ -0,0 +1,72 @@
|
||||
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
|
||||
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
|
||||
<samlp:Status>
|
||||
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
|
||||
</samlp:Status>
|
||||
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_evil" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
|
||||
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
||||
<ds:Reference URI="#pfxa06693ef-cec7-f4a6-cb7f-ad074445a1a3"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>zNDuGxwP4gVkv/Dzt7kiKo/4gzk=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>GLP/vE8uxerB0uDpPslUgLPBL6ePQB619MoQ0I2Y5lAtFE6CB1zh8BnzChRx/bFjNy4byfOe8mFfM0r7WUi1PJOFWyUPoatdLl7wHHBIRTnPpYmu3Tb2Gz0sOP0F8wW7JkBft5gJfVw49nk5si9/3Q3o52jnJZ7dPtqfIOh8uNeopikK0HLF6sU05qCCtjcXfniEnLQFNBFMo9uY5GQqmR5n3nqPz1wYyyfFOAbVmGgBIoO2PfGX2GVLQhltc9qf2JMhks4jgZsZ8iLUIiH1lcLGWZEEs94k8k0P6gSv1uZ7Vbhksd/N9Jq9pCVuEJ/jRPcAdVjzbxqKQAj6ELwr8O6fepTzA+CAdwEolBnx/C6TmSbVZ+IWk6QUGe4x4+IAukC+0hkKENlO0ELOScksvyhpgHbxNA4rp+DhGupCaO/I2RrsQkmvavbqm+wSEspK7scK112SDunjDvqPHsPYgukD33T/97PxTLorg2kKP9HHJwPJKoXXeyOGcA6vwK+RqrAlZ2dLGAgcXo+sJcdCLuvxDNz9VXofBjBZIKVKdmYhm0QJaPYHtuQsAyFavQhdOBOmGHb7QX3YE3Xy4dX4LymtT+Jlb1I4FJSht/9HUIHW1FdhfDak4f7gUgjuMamMddLD0jVgeESupSREzFv/gj2IrctkbgjAO0iuuiBgKMg=</ds:SignatureValue>
|
||||
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIFUzCCAzugAwIBAgIRAL6tbNcE9Ej9gNlbGKswfFMwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAwwSYXV0aGVudGlrIDIwMjUuNi4zMB4XDTI1MDcxNTE4MDQzNloXDTI2MDcxNjE4MDQzNlowVjEqMCgGA1UEAwwhYXV0aGVudGlrIFNlbGYtc2lnbmVkIENlcnRpZmljYXRlMRIwEAYDVQQKDAlhdXRoZW50aWsxFDASBgNVBAsMC1NlbGYtc2lnbmVkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjmut/+bBRLlyrbf+WIfg8ZTw9t6VnsiU1n04nPTulpRAz4nBOoOHNRIruSpZyFeFa6x9jwn4Ma5EFUH7HqnRvhoujm8U17OglXWZt0DLCZ6S5xPmdMogFXjJDmg9okIcI/cb9VbR6I8uvm1oiaOWCr36RTiqZ6rmdjQcuUPLr1+V/LxWQI463S+5QA2HZxAGalp45MJAz2sa9iczktKMgyYlfjj1cruFARxxeheu5qIK7aQWfyPj1QlMb9mi4VQaxUwGrAui4Tq614ivRJY2SkZb0Aq/LLSQoQWYHtYyQIasrOXJm0JuPDqhINPBDowyhu8DihC3uzOpmTXLKc5UoIQk+Q1h5iH74A3/kxOJUw13FXzRiDxC/yGthPYLyFHsDiJolscMKSCqlDvEMcpM4mxFeud9sKUb71SZr8sqmJl3qtvZmKpkR4y8pN2c00p10t0htqONmr5kyPxmhz0HCrosiPYB4olNjaydKviNTtPJ7TtnPyeA3iXGzCP1e80XzUoJrDqON5/GcpYgqsP/kGj8Qvqesa4Fez+1+5pAGHN2VzQbkHAgK3s4YRXrGLTs7wg27F9T0RE28Mm0RYBkYpdp4/5PuTTulthB9mkUBSJMgENmQAYkapvonFDsJkTi39qnsddbZusOLT4z3hsA38eFEwRqnbNZVUGPIp/O1SsCAwEAAaNVMFMwUQYDVR0RAQH/BEcwRYJDRUZ4QXVLRzV6SlVUTWpWNTJoMkRJMUQ5MXdLblZKaXFwNmpwRTRTTy5zZWxmLXNpZ25lZC5nb2F1dGhlbnRpay5pbzANBgkqhkiG9w0BAQsFAAOCAgEAYLThxDVpA1OIAVK/buueRJExIWr6y4s6NtpuR8UQEcfq5hfoc4zMFGHR5+u1WFIb5siK25xh/OnS7bLdLic6AkjZSrx91+0v2Jn9gfUqbs5AJ040XzAAdx/Mb4s0+537yhB+/JXPylR1QxhGbO7koXQ5JDhAXWKCw2O1C+80mN8dbhQvDkEtsXrHrtXclcqf2TT89XAzc5HAC8NmP4SF+FafAREQB1KdaG4QAbc/gnjsX2YJD89SDL+3jMp6F7R1Ym+bWt5oWqx2tkm6HGXd3fbpfQlnfrRN60tMjjLmw1cDMhOhpdragY5zokniEUL2pKVtrxFp7V1ZpoMI0Kt5MKkOXrezi542NWSgkGehlsDLD9wtuCNem2arR0mNnMLdYkMG7G0dpAq3Tl32dgfMfyKnNyE2O/6/EeEuzUH2NfTU1p7AUQfLrf4rtNcJEs9OAPuC9vy7w9YEpF997T+FhR2Ub1C423NQj4bwlS/9f7MIBkSi1EgnQuiSGB5epxAKI3oOVrmzOpTuvr6wZXV9pM3zdfbcoGuFWP6Ix7W8G5vg+0WvoSjc2fwGXYlidEK3xlQSMAaQ4CMClpPsKLScRq1nrQGzPYoiL1DYubsOWx9ohll6+jNjKI6f79WwbHYrW4EeRIOz38+m46EDjAWZBMgrE7J/3DhgeLEVJYBA5K0=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
|
||||
<saml:Subject>
|
||||
<saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">ATTACKER_FORGED_NAMEID</saml:NameID>
|
||||
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
||||
<saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
|
||||
</saml:SubjectConfirmation>
|
||||
</saml:Subject>
|
||||
<saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
|
||||
<saml:AudienceRestriction>
|
||||
<saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
|
||||
</saml:AudienceRestriction>
|
||||
</saml:Conditions>
|
||||
<saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
|
||||
<saml:AuthnContext>
|
||||
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
|
||||
</saml:AuthnContext>
|
||||
</saml:AuthnStatement>
|
||||
<saml:AttributeStatement>
|
||||
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">ATTACKER_FORGED</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">ATTACKER_FORGED</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">ATTACKER_FORGED</saml:AttributeValue>
|
||||
<saml:AttributeValue xsi:type="xs:string">ATTACKER_FORGED</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
</saml:AttributeStatement>
|
||||
</saml:Assertion>
|
||||
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfxa06693ef-cec7-f4a6-cb7f-ad074445a1a3" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
|
||||
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
|
||||
<saml:Subject>
|
||||
<saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
|
||||
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
||||
<saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
|
||||
</saml:SubjectConfirmation>
|
||||
</saml:Subject>
|
||||
<saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
|
||||
<saml:AudienceRestriction>
|
||||
<saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
|
||||
</saml:AudienceRestriction>
|
||||
</saml:Conditions>
|
||||
<saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
|
||||
<saml:AuthnContext>
|
||||
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
|
||||
</saml:AuthnContext>
|
||||
</saml:AuthnStatement>
|
||||
<saml:AttributeStatement>
|
||||
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
|
||||
<saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
</saml:AttributeStatement>
|
||||
</saml:Assertion>
|
||||
</samlp:Response>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_resp" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"><saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion ID="pfxa06693ef-cec7-f4a6-cb7f-ad074445a1a3" Version="2.0" IssueInstant="2014-07-17T01:01:48Z"><saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
||||
<ds:Reference URI="#pfxa06693ef-cec7-f4a6-cb7f-ad074445a1a3"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>zNDuGxwP4gVkv/Dzt7kiKo/4gzk=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>GLP/vE8uxerB0uDpPslUgLPBL6ePQB619MoQ0I2Y5lAtFE6CB1zh8BnzChRx/bFjNy4byfOe8mFfM0r7WUi1PJOFWyUPoatdLl7wHHBIRTnPpYmu3Tb2Gz0sOP0F8wW7JkBft5gJfVw49nk5si9/3Q3o52jnJZ7dPtqfIOh8uNeopikK0HLF6sU05qCCtjcXfniEnLQFNBFMo9uY5GQqmR5n3nqPz1wYyyfFOAbVmGgBIoO2PfGX2GVLQhltc9qf2JMhks4jgZsZ8iLUIiH1lcLGWZEEs94k8k0P6gSv1uZ7Vbhksd/N9Jq9pCVuEJ/jRPcAdVjzbxqKQAj6ELwr8O6fepTzA+CAdwEolBnx/C6TmSbVZ+IWk6QUGe4x4+IAukC+0hkKENlO0ELOScksvyhpgHbxNA4rp+DhGupCaO/I2RrsQkmvavbqm+wSEspK7scK112SDunjDvqPHsPYgukD33T/97PxTLorg2kKP9HHJwPJKoXXeyOGcA6vwK+RqrAlZ2dLGAgcXo+sJcdCLuvxDNz9VXofBjBZIKVKdmYhm0QJaPYHtuQsAyFavQhdOBOmGHb7QX3YE3Xy4dX4LymtT+Jlb1I4FJSht/9HUIHW1FdhfDak4f7gUgjuMamMddLD0jVgeESupSREzFv/gj2IrctkbgjAO0iuuiBgKMg=</ds:SignatureValue>
|
||||
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIFUzCCAzugAwIBAgIRAL6tbNcE9Ej9gNlbGKswfFMwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAwwSYXV0aGVudGlrIDIwMjUuNi4zMB4XDTI1MDcxNTE4MDQzNloXDTI2MDcxNjE4MDQzNlowVjEqMCgGA1UEAwwhYXV0aGVudGlrIFNlbGYtc2lnbmVkIENlcnRpZmljYXRlMRIwEAYDVQQKDAlhdXRoZW50aWsxFDASBgNVBAsMC1NlbGYtc2lnbmVkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjmut/+bBRLlyrbf+WIfg8ZTw9t6VnsiU1n04nPTulpRAz4nBOoOHNRIruSpZyFeFa6x9jwn4Ma5EFUH7HqnRvhoujm8U17OglXWZt0DLCZ6S5xPmdMogFXjJDmg9okIcI/cb9VbR6I8uvm1oiaOWCr36RTiqZ6rmdjQcuUPLr1+V/LxWQI463S+5QA2HZxAGalp45MJAz2sa9iczktKMgyYlfjj1cruFARxxeheu5qIK7aQWfyPj1QlMb9mi4VQaxUwGrAui4Tq614ivRJY2SkZb0Aq/LLSQoQWYHtYyQIasrOXJm0JuPDqhINPBDowyhu8DihC3uzOpmTXLKc5UoIQk+Q1h5iH74A3/kxOJUw13FXzRiDxC/yGthPYLyFHsDiJolscMKSCqlDvEMcpM4mxFeud9sKUb71SZr8sqmJl3qtvZmKpkR4y8pN2c00p10t0htqONmr5kyPxmhz0HCrosiPYB4olNjaydKviNTtPJ7TtnPyeA3iXGzCP1e80XzUoJrDqON5/GcpYgqsP/kGj8Qvqesa4Fez+1+5pAGHN2VzQbkHAgK3s4YRXrGLTs7wg27F9T0RE28Mm0RYBkYpdp4/5PuTTulthB9mkUBSJMgENmQAYkapvonFDsJkTi39qnsddbZusOLT4z3hsA38eFEwRqnbNZVUGPIp/O1SsCAwEAAaNVMFMwUQYDVR0RAQH/BEcwRYJDRUZ4QXVLRzV6SlVUTWpWNTJoMkRJMUQ5MXdLblZKaXFwNmpwRTRTTy5zZWxmLXNpZ25lZC5nb2F1dGhlbnRpay5pbzANBgkqhkiG9w0BAQsFAAOCAgEAYLThxDVpA1OIAVK/buueRJExIWr6y4s6NtpuR8UQEcfq5hfoc4zMFGHR5+u1WFIb5siK25xh/OnS7bLdLic6AkjZSrx91+0v2Jn9gfUqbs5AJ040XzAAdx/Mb4s0+537yhB+/JXPylR1QxhGbO7koXQ5JDhAXWKCw2O1C+80mN8dbhQvDkEtsXrHrtXclcqf2TT89XAzc5HAC8NmP4SF+FafAREQB1KdaG4QAbc/gnjsX2YJD89SDL+3jMp6F7R1Ym+bWt5oWqx2tkm6HGXd3fbpfQlnfrRN60tMjjLmw1cDMhOhpdragY5zokniEUL2pKVtrxFp7V1ZpoMI0Kt5MKkOXrezi542NWSgkGehlsDLD9wtuCNem2arR0mNnMLdYkMG7G0dpAq3Tl32dgfMfyKnNyE2O/6/EeEuzUH2NfTU1p7AUQfLrf4rtNcJEs9OAPuC9vy7w9YEpF997T+FhR2Ub1C423NQj4bwlS/9f7MIBkSi1EgnQuiSGB5epxAKI3oOVrmzOpTuvr6wZXV9pM3zdfbcoGuFWP6Ix7W8G5vg+0WvoSjc2fwGXYlidEK3xlQSMAaQ4CMClpPsKLScRq1nrQGzPYoiL1DYubsOWx9ohll6+jNjKI6f79WwbHYrW4EeRIOz38+m46EDjAWZBMgrE7J/3DhgeLEVJYBA5K0=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">FORGED_VICTIM</saml:NameID></saml:Subject><saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z"><saml:AudienceRestriction><saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:Advice><saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfxa06693ef-cec7-f4a6-cb7f-ad074445a1a3" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
|
||||
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
|
||||
<saml:Subject>
|
||||
<saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
|
||||
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
||||
<saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
|
||||
</saml:SubjectConfirmation>
|
||||
</saml:Subject>
|
||||
<saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
|
||||
<saml:AudienceRestriction>
|
||||
<saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
|
||||
</saml:AudienceRestriction>
|
||||
</saml:Conditions>
|
||||
<saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
|
||||
<saml:AuthnContext>
|
||||
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
|
||||
</saml:AuthnContext>
|
||||
</saml:AuthnStatement>
|
||||
<saml:AttributeStatement>
|
||||
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
|
||||
<saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
|
||||
<saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
</saml:AttributeStatement>
|
||||
</saml:Assertion></saml:Advice></saml:Assertion></samlp:Response>
|
||||
@@ -0,0 +1,40 @@
|
||||
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_resp_uri_empty" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"><saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
||||
<SignedInfo>
|
||||
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<Reference URI="">
|
||||
<Transforms>
|
||||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
</Transforms>
|
||||
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<DigestValue>h6La1VQZ6VO/Bi/a3g2Uhkp27kV1ijJvIB6xlgLGu7M=</DigestValue>
|
||||
</Reference>
|
||||
</SignedInfo>
|
||||
<SignatureValue>ItqDe3xfN9sN44z9pudYI+GdVEz7MnLXvG3+afjS8ws52c8fUryoK0lgH3l0i3mY
|
||||
cFKiQwiuRx86AB6uGH13ToOoXq3peK911PeGZ/fCt15x14x6v69r9vG+Mw4KAc+y
|
||||
7J/a3BOltEoU9SfNHBAIkEgbHP35bF5iYSVlIfLho8BRCVT4rMv/K/n65Hd88Fas
|
||||
Es2oxS95hYUf1of9pHDOuvEYM+VpMZw3OuMci7X8ZszCxdJbgP6D4m7w9wWBbAAi
|
||||
xWWuLnU2sFkLNeBh5KuumLNLG1Dreqiz0d4/tu+P9F4NcP2FAdG79/Y+Ga9d0Wf7
|
||||
yf05WcieZgV4hhHNwQcauw==</SignatureValue>
|
||||
<KeyInfo>
|
||||
<X509Data>
|
||||
<X509Certificate>MIICvjCCAaagAwIBAgIUGjmjYk5z7ya8VH2Faah5vvVmEHIwDQYJKoZIhvcNAQEL
|
||||
BQAwGTEXMBUGA1UEAwwOVVJJLWVtcHR5IHRlc3QwHhcNMTQwMTAxMDAwMDAwWhcN
|
||||
MzAwMTAxMDAwMDAwWjAZMRcwFQYDVQQDDA5VUkktZW1wdHkgdGVzdDCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKEuJi9Gny9OfQScZEG1R9Gy5pqbM7it
|
||||
pGda6gm4PXuFQisMapdg0DwO3odY1grTQE6gFEjSCYtEoGyuJMSUNdILvc7sfCWa
|
||||
QkuXCnkx7nXgyiHLNuhgkhw6kDXgRMzdaI/B7IlZkZYnfyXWi6A6lQ6dLJRU1p0o
|
||||
C+JawKngvmOAAKvhaC1keEbfUh//8UhK/YkjJShV1c0ijFlucj4eYDQyf9x9lYw7
|
||||
oukjnVFKmhqiRO/SxwhYjYbyTppVRzC4sCJz0KRn4qwnGV5x2+jDqUvFUxJc5W7f
|
||||
N+utrfNWeszmP5Elw+ezIsq+3D9ss+nHmtXIDxVNA3dp8tZQKzQ4WzcCAwEAATAN
|
||||
BgkqhkiG9w0BAQsFAAOCAQEART2PW/rXPU5d+NTJnP2mdIi5Ft01gpaRgY1iBsFm
|
||||
+D6zXT/k9wr56GEDLWUf2qOJeXsNc+f9FKI0BCVb/5vVoB60AAMHKbb+NxwoXLHi
|
||||
dT6DaEPK1VGdEBnpL5uOII3pO42FMPewBUNuoUmb9zipyPoL6zbc7khRcBBIYMlr
|
||||
05Y2tqJqECNAtGQ9+v5CBcECP3QI4L0UmCJMwpj7XH5TrfKfLPZuUEvQaET63dXb
|
||||
ioi+P6KEpuxblOL0Uj2e2erhJYavqCnoxt+0eUDDBsrwuk7/sRtbBO0XjkgEtJZ8
|
||||
n3OS74cjqIwTx+PqObGThECnyBYwONY7RWU5G4r6kqMXBg==
|
||||
</X509Certificate>
|
||||
</X509Data>
|
||||
</KeyInfo>
|
||||
</Signature><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion ID="_assert" Version="2.0" IssueInstant="2014-07-17T01:01:48Z"><saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">test_user</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z"><saml:AudienceRestriction><saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionIndex="_session"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion></samlp:Response>
|
||||
@@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC0jCCAbqgAwIBAgIUXHr2/LJAqtsJ4CcXkFjMwJo8HmQwDQYJKoZIhvcNAQEL
|
||||
BQAwIzEhMB8GA1UEAwwYVVJJLWVtcHR5IGFzc2VydGlvbiB0ZXN0MB4XDTE0MDEw
|
||||
MTAwMDAwMFoXDTMwMDEwMTAwMDAwMFowIzEhMB8GA1UEAwwYVVJJLWVtcHR5IGFz
|
||||
c2VydGlvbiB0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArzIB
|
||||
E4WYhfFNJk2VcvxTX9+cdyJ+v+GCAU4BxSJ1/97BPf3UN4yob23qohnnnMlGAO2x
|
||||
QBK2VBQKjNZo3qwy2t5xhsa0YLjjWGxAEL1s5K8cQlkYwkciTy+RFpMXmM80kk8p
|
||||
ZdZFgrjf5ltincH4QuhJcN3/fsEibHQibymWeb/0I3Mba6Uh+gssMN82NYETl677
|
||||
I+5HV4wgJWMh1vaZFbid+YFBeWWJoIAIdbTQEAwIJriTA43lgbcK0Lo9A8/RCH1O
|
||||
RVsQSkpA3kfs9yJ9AvKglBIThapR1iRgtVsC9LdiauHmiNU+8POSHXWByXaWOK0o
|
||||
Izfg/lI+xKSWJerhUwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA+/3kRE6jYFfgy
|
||||
vHZdOX2cFOA5Y0N/RZmdt34tsfCiqP2vHtfQUje8gQAhjmV6dFk4wptPF1FsP601
|
||||
bMp+9LsRsb4y6pxy5m7xKVK9P/EI33N2zZZL9tlJ7CPIA81DPi53lYOvX54UIi2I
|
||||
GpF6QyYMX2HTs/KVxo4gYnOnkyqPw6QrKaWpJLQndQd1rTn4/ybWW/9XU46RYf7/
|
||||
7Z8H8t4n4lhPYm5WGer4eG+k+F3R04yhwSm3Wi91gkQwQdGPgFSPe1z8TusDw/Q/
|
||||
1ax1a/mNoN9NCcZgg3L0xZgbtDnzBr/Gd/MWBQdDgRM7DpcWaVVcXq5GRLLeAvwM
|
||||
uF73araE
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICvjCCAaagAwIBAgIUGjmjYk5z7ya8VH2Faah5vvVmEHIwDQYJKoZIhvcNAQEL
|
||||
BQAwGTEXMBUGA1UEAwwOVVJJLWVtcHR5IHRlc3QwHhcNMTQwMTAxMDAwMDAwWhcN
|
||||
MzAwMTAxMDAwMDAwWjAZMRcwFQYDVQQDDA5VUkktZW1wdHkgdGVzdDCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKEuJi9Gny9OfQScZEG1R9Gy5pqbM7it
|
||||
pGda6gm4PXuFQisMapdg0DwO3odY1grTQE6gFEjSCYtEoGyuJMSUNdILvc7sfCWa
|
||||
QkuXCnkx7nXgyiHLNuhgkhw6kDXgRMzdaI/B7IlZkZYnfyXWi6A6lQ6dLJRU1p0o
|
||||
C+JawKngvmOAAKvhaC1keEbfUh//8UhK/YkjJShV1c0ijFlucj4eYDQyf9x9lYw7
|
||||
oukjnVFKmhqiRO/SxwhYjYbyTppVRzC4sCJz0KRn4qwnGV5x2+jDqUvFUxJc5W7f
|
||||
N+utrfNWeszmP5Elw+ezIsq+3D9ss+nHmtXIDxVNA3dp8tZQKzQ4WzcCAwEAATAN
|
||||
BgkqhkiG9w0BAQsFAAOCAQEART2PW/rXPU5d+NTJnP2mdIi5Ft01gpaRgY1iBsFm
|
||||
+D6zXT/k9wr56GEDLWUf2qOJeXsNc+f9FKI0BCVb/5vVoB60AAMHKbb+NxwoXLHi
|
||||
dT6DaEPK1VGdEBnpL5uOII3pO42FMPewBUNuoUmb9zipyPoL6zbc7khRcBBIYMlr
|
||||
05Y2tqJqECNAtGQ9+v5CBcECP3QI4L0UmCJMwpj7XH5TrfKfLPZuUEvQaET63dXb
|
||||
ioi+P6KEpuxblOL0Uj2e2erhJYavqCnoxt+0eUDDBsrwuk7/sRtbBO0XjkgEtJZ8
|
||||
n3OS74cjqIwTx+PqObGThECnyBYwONY7RWU5G4r6kqMXBg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -196,10 +196,122 @@ class TestResponseProcessor(TestCase):
|
||||
self.assertNotEqual(parser._get_name_id()[1], "bad")
|
||||
self.assertEqual(parser._get_name_id()[1], "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7")
|
||||
|
||||
@freeze_time("2022-10-14T14:15:00")
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_verification_assertion_xsw_nested_duplicate_id(self):
|
||||
"""Nested-duplicate-ID XSW: a forged outer Assertion shares its ID with a
|
||||
nested copy of the original signed Assertion (placed inside <saml:Advice>),
|
||||
so the Signature's Reference URI (#ORIG_ID) matches the outer Assertion's
|
||||
ID *and* dereferences to legitimately-signed content. Must be rejected."""
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
kp = CertificateKeyPair.objects.create(
|
||||
name=generate_id(),
|
||||
certificate_data=key,
|
||||
)
|
||||
self.source.verification_kp = kp
|
||||
self.source.signed_assertion = True
|
||||
self.source.signed_response = False
|
||||
request = self.factory.post(
|
||||
"/",
|
||||
data={
|
||||
"SAMLResponse": b64encode(
|
||||
load_fixture("fixtures/response_signed_assertion_xsw_nested.xml").encode()
|
||||
).decode()
|
||||
},
|
||||
)
|
||||
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
with self.assertRaises(InvalidSignature):
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_verification_response_uri_empty(self):
|
||||
"""Some real-world IdPs (notably some Okta dev-tenant configurations
|
||||
observed in the gosaml2 testdata corpus at saml.oktadev.com) sign the
|
||||
Response with ds:Reference URI="" instead of URI="#<ID>". Per xmldsig
|
||||
§4.4.3.2, URI="" covers the entire enclosing document via the
|
||||
enveloped-signature transform — strictly more attested content than
|
||||
"#<ID>" — so consuming the target is a subset of what was signed."""
|
||||
key = load_fixture("fixtures/signature_cert_uri_empty.pem")
|
||||
kp = CertificateKeyPair.objects.create(
|
||||
name=generate_id(),
|
||||
certificate_data=key,
|
||||
)
|
||||
self.source.verification_kp = kp
|
||||
self.source.signed_response = True
|
||||
self.source.signed_assertion = False
|
||||
request = self.factory.post(
|
||||
"/",
|
||||
data={
|
||||
"SAMLResponse": b64encode(
|
||||
load_fixture("fixtures/response_signed_response_uri_empty.xml").encode()
|
||||
).decode()
|
||||
},
|
||||
)
|
||||
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_verification_assertion_uri_empty(self):
|
||||
"""Symmetric to test_verification_response_uri_empty but for an
|
||||
Assertion-level signature: the same xmldsig "this document" semantics
|
||||
still cover the whole enclosing document, so the Assertion we then
|
||||
consume is part of the attested content. We have no real-world IdP
|
||||
samples emitting this configuration, but the pre-fix code accepted it
|
||||
and the cryptographic guarantee holds, so keep accepting it rather
|
||||
than risk breaking an IdP we haven't sampled."""
|
||||
key = load_fixture("fixtures/signature_cert_assertion_uri_empty.pem")
|
||||
kp = CertificateKeyPair.objects.create(
|
||||
name=generate_id(),
|
||||
certificate_data=key,
|
||||
)
|
||||
self.source.verification_kp = kp
|
||||
self.source.signed_assertion = True
|
||||
self.source.signed_response = False
|
||||
request = self.factory.post(
|
||||
"/",
|
||||
data={
|
||||
"SAMLResponse": b64encode(
|
||||
load_fixture("fixtures/response_signed_assertion_uri_empty.xml").encode()
|
||||
).decode()
|
||||
},
|
||||
)
|
||||
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_verification_assertion_xsw3(self):
|
||||
"""XSW-3 (signature relocation): a forged Assertion contains a Signature whose
|
||||
ds:Reference URI points to a second Assertion in the document. The signature
|
||||
verifies (because the digest matches the legitimate referenced Assertion),
|
||||
but the verifier must NOT then consume the forged Assertion as if it were
|
||||
signed."""
|
||||
key = load_fixture("fixtures/signature_cert.pem")
|
||||
kp = CertificateKeyPair.objects.create(
|
||||
name=generate_id(),
|
||||
certificate_data=key,
|
||||
)
|
||||
self.source.verification_kp = kp
|
||||
self.source.signed_assertion = True
|
||||
self.source.signed_response = False
|
||||
request = self.factory.post(
|
||||
"/",
|
||||
data={
|
||||
"SAMLResponse": b64encode(
|
||||
load_fixture("fixtures/response_signed_assertion_xsw3.xml").encode()
|
||||
).decode()
|
||||
},
|
||||
)
|
||||
|
||||
parser = ResponseProcessor(self.source, request)
|
||||
with self.assertRaises(InvalidSignature):
|
||||
parser.parse()
|
||||
|
||||
@freeze_time("2014-07-17T01:02:18Z")
|
||||
def test_name_id_comment(self):
|
||||
"""Test comment in name ID"""
|
||||
fixture = load_fixture("fixtures/response_signed_assertion_dup.xml")
|
||||
fixture = load_fixture("fixtures/response_signed_assertion.xml")
|
||||
fixture = fixture.replace(
|
||||
"_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7",
|
||||
"_ce3d2948b4cf20146dee0a0b3dd6f<!--x-->69b6cf86f62d7",
|
||||
|
||||
@@ -291,7 +291,7 @@ class VerifyNotAllowed:
|
||||
|
||||
class ThrottlingMixin(models.Model):
|
||||
"""
|
||||
Mixin class for models that want throttling behaviour.
|
||||
Mixin class for models that want throttling behavior.
|
||||
|
||||
This implements exponential back-off for verifying tokens. Subclasses must
|
||||
implement :meth:`get_throttle_factor`, and must use the
|
||||
|
||||
@@ -362,7 +362,7 @@ class AuthenticatorSMSStageTests(FlowTestCase):
|
||||
|
||||
|
||||
class TestSMSDeviceThrottling(ThrottlingTestMixin, TestCase):
|
||||
"""Test ThrottlingMixin behaviour on SMSDevice.verify_token"""
|
||||
"""Test ThrottlingMixin behavior on SMSDevice.verify_token"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -4,6 +4,7 @@ from email.mime.image import MIMEImage
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.core.mail.message import sanitize_address
|
||||
from django.template.exceptions import TemplateDoesNotExist
|
||||
@@ -14,9 +15,10 @@ from django.utils import translation
|
||||
@lru_cache
|
||||
def logo_data() -> MIMEImage:
|
||||
"""Get logo as MIME Image for emails"""
|
||||
path = Path("web/icons/icon_left_brand.png")
|
||||
if not path.exists():
|
||||
path = Path("web/dist/assets/icons/icon_left_brand.png")
|
||||
path = Path("web/dist/assets/icons/icon_left_brand.png")
|
||||
# When running tests, assets might not exist, so fallback to a different icon
|
||||
if settings.TEST:
|
||||
path = Path("web/authentik/sources/saml.png")
|
||||
with open(path, "rb") as _logo_file:
|
||||
logo = MIMEImage(_logo_file.read())
|
||||
logo.add_header("Content-ID", "<logo>")
|
||||
|
||||
@@ -18,7 +18,7 @@ PLAN_CONTEXT_INVITATION = "invitation"
|
||||
|
||||
|
||||
class InvitationStageView(StageView):
|
||||
"""Finalise Authentication flow by logging the user in"""
|
||||
"""Finalize Authentication flow by logging the user in"""
|
||||
|
||||
def get_token(self) -> str | None:
|
||||
"""Get token from saved get-arguments or prompt_data"""
|
||||
|
||||
@@ -10,7 +10,7 @@ from authentik.flows.stage import StageView
|
||||
|
||||
|
||||
class UserDeleteStageView(StageView):
|
||||
"""Finalise unenrollment flow by deleting the user object."""
|
||||
"""Finalize unenrollment flow by deleting the user object."""
|
||||
|
||||
def dispatch(self, request: HttpRequest) -> HttpResponse:
|
||||
"""Delete currently pending user"""
|
||||
|
||||
@@ -53,7 +53,7 @@ class UserLoginChallengeResponse(ChallengeResponse):
|
||||
|
||||
|
||||
class UserLoginStageView(ChallengeStageView):
|
||||
"""Finalise Authentication flow by logging the user in"""
|
||||
"""Finalize Authentication flow by logging the user in"""
|
||||
|
||||
response_class = UserLoginChallengeResponse
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user