Merge branch 'main' into gh-16390
Signed-off-by: yoobin_mion <113106136+yybmion@users.noreply.github.com>
This commit is contained in:
commit
5d237a7822
|
@ -1,40 +0,0 @@
|
||||||
version: 2
|
|
||||||
|
|
||||||
registries:
|
|
||||||
spring-milestones:
|
|
||||||
type: maven-repository
|
|
||||||
url: https://repo.spring.io/milestone
|
|
||||||
|
|
||||||
updates:
|
|
||||||
|
|
||||||
- package-ecosystem: "gradle"
|
|
||||||
target-branch: "main"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
time: "03:00"
|
|
||||||
timezone: "Etc/UTC"
|
|
||||||
labels: [ "type: dependency-upgrade" ]
|
|
||||||
registries:
|
|
||||||
- "spring-milestones"
|
|
||||||
ignore:
|
|
||||||
- dependency-name: "com.nimbusds:nimbus-jose-jwt" # nimbus-jose-jwt gets updated when oauth2-oidc-sdk is updated to ensure consistency
|
|
||||||
- dependency-name: "org.python:jython" # jython updates break integration tests
|
|
||||||
- dependency-name: "org.apache.directory.server:*" # ApacheDS version > 1.5.5 contains break changes
|
|
||||||
- dependency-name: "org.junit:junit-bom"
|
|
||||||
update-types: [ "version-update:semver-major" ]
|
|
||||||
- dependency-name: "org.mockito:mockito-bom"
|
|
||||||
update-types: [ "version-update:semver-major" ]
|
|
||||||
- dependency-name: "*"
|
|
||||||
update-types: [ "version-update:semver-major", "version-update:semver-minor" ]
|
|
||||||
|
|
||||||
# GitHub Actions
|
|
||||||
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
target-branch: "main"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
ignore:
|
|
||||||
- dependency-name: "spring-io/*"
|
|
||||||
- dependency-name: "spring-security-release-tools/*"
|
|
|
@ -4,6 +4,32 @@ registries:
|
||||||
type: maven-repository
|
type: maven-repository
|
||||||
url: https://repo.spring.io/milestone
|
url: https://repo.spring.io/milestone
|
||||||
updates:
|
updates:
|
||||||
|
- package-ecosystem: gradle
|
||||||
|
target-branch: 6.5.x
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
time: '03:00'
|
||||||
|
timezone: Etc/UTC
|
||||||
|
labels:
|
||||||
|
- 'type: dependency-upgrade'
|
||||||
|
registries:
|
||||||
|
- spring-milestones
|
||||||
|
ignore:
|
||||||
|
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||||
|
- dependency-name: org.python:jython
|
||||||
|
- dependency-name: org.apache.directory.server:*
|
||||||
|
- dependency-name: org.apache.directory.shared:*
|
||||||
|
- dependency-name: org.junit:junit-bom
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-major
|
||||||
|
- dependency-name: org.mockito:mockito-bom
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-major
|
||||||
|
- dependency-name: '*'
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-major
|
||||||
|
- version-update:semver-minor
|
||||||
- package-ecosystem: gradle
|
- package-ecosystem: gradle
|
||||||
target-branch: 6.4.x
|
target-branch: 6.4.x
|
||||||
directory: /
|
directory: /
|
||||||
|
@ -85,17 +111,8 @@ updates:
|
||||||
- dependency-name: '*'
|
- dependency-name: '*'
|
||||||
update-types:
|
update-types:
|
||||||
- version-update:semver-major
|
- version-update:semver-major
|
||||||
|
- version-update:semver-minor
|
||||||
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
target-branch: 6.4.x
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
ignore:
|
|
||||||
- dependency-name: sjohnr/*
|
|
||||||
- package-ecosystem: github-actions
|
- package-ecosystem: github-actions
|
||||||
target-branch: 6.3.x
|
target-branch: 6.3.x
|
||||||
directory: /
|
directory: /
|
||||||
|
@ -106,14 +123,6 @@ updates:
|
||||||
- 'in: build'
|
- 'in: build'
|
||||||
ignore:
|
ignore:
|
||||||
- dependency-name: sjohnr/*
|
- dependency-name: sjohnr/*
|
||||||
- package-ecosystem: github-actions
|
|
||||||
target-branch: main
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
- package-ecosystem: github-actions
|
- package-ecosystem: github-actions
|
||||||
target-branch: docs-build
|
target-branch: docs-build
|
||||||
directory: /
|
directory: /
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: "CodeQL Advanced"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule
|
||||||
|
- cron: '0 5 * * *'
|
||||||
|
permissions: read-all
|
||||||
|
jobs:
|
||||||
|
codeql-analysis-call:
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@1
|
|
@ -39,48 +39,25 @@ jobs:
|
||||||
toolchain: 17
|
toolchain: 17
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.java-version }}
|
java-version: ${{ matrix.java-version }}
|
||||||
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.2.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2024.0.+ --stacktrace
|
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
check-samples:
|
|
||||||
name: Check Samples
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.repository_owner == 'spring-projects' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Set up gradle
|
|
||||||
uses: spring-io/spring-gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
java-version: 17
|
|
||||||
distribution: temurin
|
|
||||||
- name: Check samples project
|
|
||||||
env:
|
|
||||||
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
|
|
||||||
SAMPLES_DIR: ../spring-security-samples
|
|
||||||
run: |
|
|
||||||
# Extract version from gradle.properties
|
|
||||||
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
|
|
||||||
# Extract samplesBranch from gradle.properties
|
|
||||||
samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}')
|
|
||||||
./gradlew publishMavenJavaPublicationToLocalRepository
|
|
||||||
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR"
|
|
||||||
./gradlew --refresh-dependencies --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" test integrationTest
|
|
||||||
deploy-artifacts:
|
deploy-artifacts:
|
||||||
name: Deploy Artifacts
|
name: Deploy Artifacts
|
||||||
needs: [ build, test, check-samples ]
|
needs: [ build, test]
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1
|
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1
|
||||||
with:
|
with:
|
||||||
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
deploy-docs:
|
deploy-docs:
|
||||||
name: Deploy Docs
|
name: Deploy Docs
|
||||||
needs: [ build, test, check-samples ]
|
needs: [ build, test ]
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1
|
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1
|
||||||
with:
|
with:
|
||||||
should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }}
|
should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
deploy-schema:
|
deploy-schema:
|
||||||
name: Deploy Schema
|
name: Deploy Schema
|
||||||
needs: [ build, test, check-samples ]
|
needs: [ build, test ]
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1
|
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1
|
||||||
with:
|
with:
|
||||||
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
name: Auto Merge Forward Dependabot Commits
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: dependabot-auto-merge-forward
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
get-supported-branches:
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/retrieve-spring-supported-versions.yml@actions-v1
|
|
||||||
with:
|
|
||||||
project: spring-security
|
|
||||||
type: oss
|
|
||||||
repository_name: spring-projects/spring-security
|
|
||||||
|
|
||||||
auto-merge-forward-dependabot:
|
|
||||||
name: Auto Merge Forward Dependabot Commits
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-supported-branches]
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
id: checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
- name: Setup GitHub User
|
|
||||||
id: setup-gh-user
|
|
||||||
run: |
|
|
||||||
git config user.name 'github-actions[bot]'
|
|
||||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
|
||||||
- name: Run Auto Merge Forward
|
|
||||||
id: run-auto-merge-forward
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/actions/auto-merge-forward@actions-v1
|
|
||||||
with:
|
|
||||||
branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main
|
|
||||||
from-author: dependabot[bot]
|
|
||||||
notify_result:
|
|
||||||
name: Check for failures
|
|
||||||
needs: [ auto-merge-forward-dependabot ]
|
|
||||||
if: failure()
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
steps:
|
|
||||||
- name: Send Slack message
|
|
||||||
uses: Gamesight/slack-workflow-status@v1.3.0
|
|
||||||
with:
|
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
||||||
channel: '#spring-security-ci'
|
|
||||||
name: 'CI Notifier'
|
|
|
@ -4,7 +4,8 @@ on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 2 * * *' # 2am UTC
|
- cron: '0 2 * * *' # 2am UTC
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
jobs:
|
jobs:
|
||||||
upgrade_wrapper:
|
upgrade_wrapper:
|
||||||
name: Execution
|
name: Execution
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
name: Mark Duplicate Dependabot PRs
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [closed]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_duplicate_prs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event.pull_request.merged == true && github.event.pull_request.user.login == 'dependabot[bot]'
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Extract Dependency Name from PR Title
|
|
||||||
id: extract
|
|
||||||
run: |
|
|
||||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
|
||||||
DEPENDENCY_NAME=$(echo "$PR_TITLE" | awk -F ' from ' '{print $1}')
|
|
||||||
echo "dependency_name=$DEPENDENCY_NAME" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Find PRs
|
|
||||||
id: find_duplicates
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
PRS=$(gh pr list --search 'milestone:${{ github.event.pull_request.milestone.title }} is:merged in:title "${{ steps.extract.outputs.dependency_name }}"' --json number --jq 'map(.number) | join(",")')
|
|
||||||
echo "prs=$PRS" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Label Duplicate PRs
|
|
||||||
if: steps.find_duplicates.outputs.prs != ''
|
|
||||||
env:
|
|
||||||
PRS: ${{ steps.find_duplicates.outputs.prs }}
|
|
||||||
CURRENT_PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
for i in ${PRS//,/ }
|
|
||||||
do
|
|
||||||
if [ ! $i -eq "$CURRENT_PR_NUMBER" ]; then
|
|
||||||
echo "Marking PR $i as duplicate"
|
|
||||||
gh pr edit "$i" --add-label "status: duplicate"
|
|
||||||
gh pr comment "$i" --body "Duplicate of #$CURRENT_PR_NUMBER"
|
|
||||||
fi
|
|
||||||
done
|
|
|
@ -1,63 +0,0 @@
|
||||||
name: Merge Dependabot PR
|
|
||||||
|
|
||||||
on: pull_request_target
|
|
||||||
|
|
||||||
run-name: Merge Dependabot PR ${{ github.ref_name }}
|
|
||||||
|
|
||||||
permissions: write-all
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
merge-dependabot-pr:
|
|
||||||
name: Merge Dependabot PR
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
show-progress: false
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
- uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Set Milestone to Dependabot Pull Request
|
|
||||||
id: set-milestone
|
|
||||||
run: |
|
|
||||||
if test -f pom.xml
|
|
||||||
then
|
|
||||||
CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout)
|
|
||||||
else
|
|
||||||
CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }')
|
|
||||||
fi
|
|
||||||
export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT}
|
|
||||||
MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title')
|
|
||||||
|
|
||||||
if [ -z $MILESTONE ]
|
|
||||||
then
|
|
||||||
gh run cancel ${{ github.run_id }}
|
|
||||||
echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version"
|
|
||||||
else
|
|
||||||
gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE
|
|
||||||
echo mergeEnabled=true >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Merge Dependabot pull request
|
|
||||||
if: steps.set-milestone.outputs.mergeEnabled
|
|
||||||
run: gh pr merge ${{ github.event.pull_request.number }} --auto --rebase
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
send-notification:
|
|
||||||
name: Send Notification
|
|
||||||
needs: [ merge-dependabot-pr ]
|
|
||||||
if: ${{ failure() || cancelled() }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Notification
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
|
|
||||||
with:
|
|
||||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
|
|
@ -11,7 +11,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# List of active maintenance branches.
|
# List of active maintenance branches.
|
||||||
branch: [ main, 6.4.x, 6.3.x ]
|
branch: [ main, 6.5.x, 6.4.x, 6.3.x ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
name: Trigger Dependabot Auto Merge Forward
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*.x'
|
|
||||||
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
trigger-worflow:
|
|
||||||
name: Trigger Workflow
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event.commits[0].author.username == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
id: checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- id: trigger
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
run: gh workflow run dependabot-auto-merge-forward.yml -r main
|
|
|
@ -18,7 +18,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ]
|
branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ]
|
||||||
steps:
|
steps:
|
||||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@c2038265125ec6f305a4a041d892ee44c156a754
|
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0
|
||||||
name: Update
|
name: Update
|
||||||
with:
|
with:
|
||||||
docs-branch: ${{ matrix.branch }}
|
docs-branch: ${{ matrix.branch }}
|
||||||
|
@ -28,7 +28,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Update on docs-build
|
name: Update on docs-build
|
||||||
steps:
|
steps:
|
||||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@c2038265125ec6f305a4a041d892ee44c156a754
|
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0
|
||||||
name: Update
|
name: Update
|
||||||
with:
|
with:
|
||||||
docs-branch: 'docs-build'
|
docs-branch: 'docs-build'
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
name: Update dependabot.yml
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
get-supported-branches:
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/retrieve-spring-supported-versions.yml@actions-v1
|
|
||||||
with:
|
|
||||||
project: spring-security
|
|
||||||
type: oss
|
|
||||||
repository_name: spring-projects/spring-security
|
|
||||||
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-supported-branches]
|
|
||||||
if: ${{ (github.repository == 'spring-projects/spring-security') && (github.ref == 'refs/heads/main') }}
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
- uses: spring-io/spring-security-release-tools/.github/actions/generate-dependabot-yml@actions-v1
|
|
||||||
name: Update dependabot.yml
|
|
||||||
with:
|
|
||||||
gradle-branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main
|
|
||||||
github-actions-branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main,docs-build
|
|
||||||
gh-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
|
||||||
with:
|
|
||||||
commit_message: Update dependabot.yml
|
|
|
@ -79,7 +79,10 @@ See https://github.com/spring-projects/spring-security/tree/main#building-from-s
|
||||||
|
|
||||||
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
|
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
|
||||||
|
|
||||||
To format the code as well as check the style, run `./gradlew format check`.
|
Additionally, since Streams are https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loops, please use them judiciously.
|
||||||
|
The team may ask you to change to a `for` loop if the given code is along a hot path.
|
||||||
|
|
||||||
|
To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
|
||||||
|
|
||||||
[[submit-a-pull-request]]
|
[[submit-a-pull-request]]
|
||||||
=== Submit a Pull Request
|
=== Submit a Pull Request
|
||||||
|
@ -104,7 +107,7 @@ If this is for an issue, consider a branch name with the issue number, like `gh-
|
||||||
6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
|
6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
|
||||||
7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
|
7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
|
||||||
8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
|
8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
|
||||||
9. [[format-code]] For each commit, build the code using `./gradlew format check`.
|
9. [[format-code]] For each commit, build the code using `./gradlew format && ./gradlew check`.
|
||||||
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
|
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
|
||||||
10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent
|
10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent
|
||||||
multiple edits or corrections of the same logical change.
|
multiple edits or corrections of the same logical change.
|
||||||
|
|
|
@ -100,8 +100,8 @@ public class JdbcAclService implements AclService {
|
||||||
@Override
|
@Override
|
||||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||||
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
|
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
|
||||||
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
|
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql,
|
||||||
(rs, rowNum) -> mapObjectIdentityRow(rs));
|
(rs, rowNum) -> mapObjectIdentityRow(rs), args);
|
||||||
return (!objects.isEmpty()) ? objects : null;
|
return (!objects.isEmpty()) ? objects : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,8 +190,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||||
* @return the primary key or null if not found
|
* @return the primary key or null if not found
|
||||||
*/
|
*/
|
||||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||||
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, new Object[] { type },
|
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
|
||||||
Long.class);
|
|
||||||
|
|
||||||
if (!classIds.isEmpty()) {
|
if (!classIds.isEmpty()) {
|
||||||
return classIds.get(0);
|
return classIds.get(0);
|
||||||
|
@ -242,8 +241,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||||
* @return the primary key or null if not found
|
* @return the primary key or null if not found
|
||||||
*/
|
*/
|
||||||
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
|
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
|
||||||
List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey,
|
List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidIsPrincipal,
|
||||||
new Object[] { sidIsPrincipal, sidName }, Long.class);
|
sidName);
|
||||||
if (!sidIds.isEmpty()) {
|
if (!sidIds.isEmpty()) {
|
||||||
return sidIds.get(0);
|
return sidIds.get(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ public class JdbcAclServiceTests {
|
||||||
List<ObjectIdentity> result = new ArrayList<>();
|
List<ObjectIdentity> result = new ArrayList<>();
|
||||||
result.add(new ObjectIdentityImpl(Object.class, "5577"));
|
result.add(new ObjectIdentityImpl(Object.class, "5577"));
|
||||||
Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" };
|
Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" };
|
||||||
given(this.jdbcOperations.query(anyString(), eq(args), any(RowMapper.class))).willReturn(result);
|
given(this.jdbcOperations.query(anyString(), any(RowMapper.class), eq(args))).willReturn(result);
|
||||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L);
|
ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L);
|
||||||
List<ObjectIdentity> objectIdentities = this.aclService.findChildren(objectIdentity);
|
List<ObjectIdentity> objectIdentities = this.aclService.findChildren(objectIdentity);
|
||||||
assertThat(objectIdentities).hasSize(1);
|
assertThat(objectIdentities).hasSize(1);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -144,7 +144,7 @@ public class PreAuthorizeAspectTests {
|
||||||
protected void protectedMethod() {
|
protected void protectedMethod() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('X')")
|
@PreAuthorize("hasRole('A')")
|
||||||
void publicCallsPrivate() {
|
void publicCallsPrivate() {
|
||||||
privateMethod();
|
privateMethod();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "java-gradle-plugin"
|
id "java-gradle-plugin"
|
||||||
|
id "groovy-gradle-plugin"
|
||||||
id "java"
|
id "java"
|
||||||
id "groovy"
|
id "groovy"
|
||||||
}
|
}
|
||||||
|
@ -76,6 +77,7 @@ dependencies {
|
||||||
implementation libs.com.github.spullara.mustache.java.compiler
|
implementation libs.com.github.spullara.mustache.java.compiler
|
||||||
implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin
|
implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin
|
||||||
implementation libs.io.spring.nohttp.nohttp.gradle
|
implementation libs.io.spring.nohttp.nohttp.gradle
|
||||||
|
implementation libs.org.jetbrains.kotlin.kotlin.gradle.plugin
|
||||||
implementation (libs.net.sourceforge.htmlunit) {
|
implementation (libs.net.sourceforge.htmlunit) {
|
||||||
exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client'
|
exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client'
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class ManagementConfigurationPlugin implements Plugin<Project> {
|
||||||
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
|
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
|
||||||
publishing.getPublications().withType(MavenPublication.class, (mavenPublication -> {
|
publishing.getPublications().withType(MavenPublication.class, (mavenPublication -> {
|
||||||
mavenPublication.versionMapping((versions) ->
|
mavenPublication.versionMapping((versions) ->
|
||||||
versions.allVariants(versionMapping -> versionMapping.fromResolutionResult())
|
versions.allVariants((versionMapping) -> versionMapping.fromResolutionResult())
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
|
@ -80,6 +80,11 @@ class RepositoryConventionPlugin implements Plugin<Project> {
|
||||||
}
|
}
|
||||||
url = 'https://repo.spring.io/release/'
|
url = 'https://repo.spring.io/release/'
|
||||||
}
|
}
|
||||||
|
forceMavenRepositories.findAll { it.startsWith('https://') || it.startsWith('file://') }.each { mavenUrl ->
|
||||||
|
maven {
|
||||||
|
url mavenUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,13 @@ public class SchemaZipPlugin implements Plugin<Project> {
|
||||||
for (def key : schemas.keySet()) {
|
for (def key : schemas.keySet()) {
|
||||||
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
|
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
|
||||||
assert shortName != key
|
assert shortName != key
|
||||||
|
def schemaResourceName = schemas.get(key)
|
||||||
File xsdFile = module.sourceSets.main.resources.find {
|
File xsdFile = module.sourceSets.main.resources.find {
|
||||||
it.path.endsWith(schemas.get(key))
|
it.path.endsWith(schemaResourceName)
|
||||||
|
}
|
||||||
|
if (xsdFile == null) {
|
||||||
|
throw new IllegalStateException("Could not find schema file for resource name " + schemaResourceName + " in src/main/resources")
|
||||||
}
|
}
|
||||||
assert xsdFile != null
|
|
||||||
schemaZip.into (shortName) {
|
schemaZip.into (shortName) {
|
||||||
duplicatesStrategy 'exclude'
|
duplicatesStrategy 'exclude'
|
||||||
from xsdFile.path
|
from xsdFile.path
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'kotlin'
|
||||||
|
}
|
||||||
|
|
||||||
|
project.plugins.withId("org.jetbrains.kotlin.jvm", (kotlinProject) -> {
|
||||||
|
project.tasks.withType(KotlinCompile).configureEach {
|
||||||
|
kotlinOptions {
|
||||||
|
languageVersion = '2.2'
|
||||||
|
apiVersion = '2.2'
|
||||||
|
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
|
||||||
|
jvmTarget = '17'
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -81,9 +81,6 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask {
|
||||||
if (group.startsWith("javax")) {
|
if (group.startsWith("javax")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (group.equals("commons-logging")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
|
if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class CheckExpectedBranchVersionPlugin implements Plugin<Project> {
|
||||||
task.setDescription("Check if the project version matches the branch version");
|
task.setDescription("Check if the project version matches the branch version");
|
||||||
task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent);
|
task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent);
|
||||||
task.getVersion().convention(project.provider(() -> project.getVersion().toString()));
|
task.getVersion().convention(project.provider(() -> project.getVersion().toString()));
|
||||||
task.getBranchName().convention(project.getProviders().exec(execSpec -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText());
|
task.getBranchName().convention(project.getProviders().exec((execSpec) -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText());
|
||||||
task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version"));
|
task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version"));
|
||||||
});
|
});
|
||||||
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask));
|
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask));
|
||||||
|
|
|
@ -4,7 +4,7 @@ import trang.RncToXsd
|
||||||
|
|
||||||
apply plugin: 'io.spring.convention.spring-module'
|
apply plugin: 'io.spring.convention.spring-module'
|
||||||
apply plugin: 'trang'
|
apply plugin: 'trang'
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'security-kotlin'
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
opensaml5 {
|
opensaml5 {
|
||||||
|
@ -78,12 +78,6 @@ dependencies {
|
||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
exclude group: 'xml-apis', module: 'xml-apis'
|
exclude group: 'xml-apis', module: 'xml-apis'
|
||||||
}
|
}
|
||||||
testImplementation "org.apache.directory.server:apacheds-core"
|
|
||||||
testImplementation "org.apache.directory.server:apacheds-core-entry"
|
|
||||||
testImplementation "org.apache.directory.server:apacheds-protocol-shared"
|
|
||||||
testImplementation "org.apache.directory.server:apacheds-protocol-ldap"
|
|
||||||
testImplementation "org.apache.directory.server:apacheds-server-jndi"
|
|
||||||
testImplementation 'org.apache.directory.shared:shared-ldap'
|
|
||||||
testImplementation "com.unboundid:unboundid-ldapsdk"
|
testImplementation "com.unboundid:unboundid-ldapsdk"
|
||||||
testImplementation 'jakarta.persistence:jakarta.persistence-api'
|
testImplementation 'jakarta.persistence:jakarta.persistence-api'
|
||||||
testImplementation "org.hibernate.orm:hibernate-core"
|
testImplementation "org.hibernate.orm:hibernate-core"
|
||||||
|
@ -127,6 +121,7 @@ dependencies {
|
||||||
|
|
||||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
testRuntimeOnly 'org.hsqldb:hsqldb'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
|
||||||
}
|
}
|
||||||
|
|
||||||
def rncToXsd = tasks.named('rncToXsd', RncToXsd)
|
def rncToXsd = tasks.named('rncToXsd', RncToXsd)
|
||||||
|
@ -158,15 +153,6 @@ tasks.named('sourcesJar', Jar).configure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(KotlinCompile).configureEach {
|
|
||||||
kotlinOptions {
|
|
||||||
languageVersion = "1.7"
|
|
||||||
apiVersion = "1.7"
|
|
||||||
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
|
|
||||||
jvmTarget = "17"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(project.tasks.withType(Test)) {
|
configure(project.tasks.withType(Test)) {
|
||||||
doFirst {
|
doFirst {
|
||||||
systemProperties['springSecurityVersion'] = version
|
systemProperties['springSecurityVersion'] = version
|
||||||
|
|
|
@ -44,7 +44,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
@ -326,11 +326,11 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
|
||||||
abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ApacheDSContainer ldapServer() throws Exception {
|
UnboundIdContainer ldapServer() throws Exception {
|
||||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org",
|
UnboundIdContainer unboundIdContainer = new UnboundIdContainer("dc=springframework,dc=org",
|
||||||
"classpath:/test-server.ldif");
|
"classpath:/test-server.ldif");
|
||||||
apacheDSContainer.setPort(getPort());
|
unboundIdContainer.setPort(getPort());
|
||||||
return apacheDSContainer;
|
return unboundIdContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,8 +74,7 @@ public class HelloRSocketITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -87,8 +87,7 @@ public class HelloRSocketObservationITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -74,8 +74,7 @@ public class HelloRSocketWithWebFluxITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -86,8 +86,7 @@ public class JwtITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -81,8 +81,7 @@ public class RSocketMessageHandlerConnectionITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -79,8 +79,7 @@ public class RSocketMessageHandlerITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -79,8 +79,7 @@ public class SimpleAuthenticationITests {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
this.server = RSocketServer.create()
|
this.server = RSocketServer.create()
|
||||||
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
.payloadDecoder(PayloadDecoder.ZERO_COPY)
|
||||||
.interceptors((registry) ->
|
.interceptors((registry) -> registry.forSocketAcceptor(this.interceptor)
|
||||||
registry.forSocketAcceptor(this.interceptor)
|
|
||||||
)
|
)
|
||||||
.acceptor(this.handler.responder())
|
.acceptor(this.handler.responder())
|
||||||
.bind(TcpServerTransport.create("localhost", 0))
|
.bind(TcpServerTransport.create("localhost", 0))
|
||||||
|
|
|
@ -43,7 +43,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||||
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
||||||
|
@ -226,18 +226,18 @@ public class LdapBindAuthenticationManagerFactoryITests {
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||||
|
|
||||||
private ApacheDSContainer container;
|
private UnboundIdContainer container;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ApacheDSContainer ldapServer() throws Exception {
|
UnboundIdContainer ldapServer() {
|
||||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||||
this.container.setPort(0);
|
this.container.setPort(0);
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||||
int port = container.getLocalPort();
|
int port = container.getPort();
|
||||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||||
|
@ -93,18 +93,18 @@ public class LdapPasswordComparisonAuthenticationManagerFactoryITests {
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||||
|
|
||||||
private ApacheDSContainer container;
|
private UnboundIdContainer container;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ApacheDSContainer ldapServer() throws Exception {
|
UnboundIdContainer ldapServer() {
|
||||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||||
this.container.setPort(0);
|
this.container.setPort(0);
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||||
int port = container.getLocalPort();
|
int port = container.getPort();
|
||||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||||
AuthenticationManager.class);
|
AuthenticationManager.class);
|
||||||
Authentication auth = authenticationManager
|
Authentication auth = authenticationManager
|
||||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("otherben", "otherbenspassword"));
|
||||||
UserDetails ben = (UserDetails) auth.getPrincipal();
|
UserDetails ben = (UserDetails) auth.getPrincipal();
|
||||||
assertThat(ben.getAuthorities()).hasSize(3);
|
assertThat(ben.getAuthorities()).hasSize(3);
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,27 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||||
assertThat(auth).isNotNull();
|
assertThat(auth).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void supportsShaPasswordEncoder() {
|
||||||
|
this.appCtx = new InMemoryXmlApplicationContext("""
|
||||||
|
<ldap-server ldif='classpath:test-server.ldif' port='0'/>
|
||||||
|
<authentication-manager>
|
||||||
|
<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>
|
||||||
|
<password-compare>
|
||||||
|
<password-encoder ref='pe' />
|
||||||
|
</password-compare>
|
||||||
|
</ldap-authentication-provider>
|
||||||
|
</authentication-manager>
|
||||||
|
<b:bean id='pe' class='org.springframework.security.crypto.password.LdapShaPasswordEncoder' />
|
||||||
|
""");
|
||||||
|
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||||
|
AuthenticationManager.class);
|
||||||
|
Authentication auth = authenticationManager
|
||||||
|
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||||
|
|
||||||
|
assertThat(auth).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void inetOrgContextMapperIsSupported() {
|
public void inetOrgContextMapperIsSupported() {
|
||||||
this.appCtx = new InMemoryXmlApplicationContext(
|
this.appCtx = new InMemoryXmlApplicationContext(
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.springframework.ldap.core.LdapTemplate;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -92,9 +92,9 @@ public class LdapServerBeanDefinitionParserTests {
|
||||||
@Test
|
@Test
|
||||||
public void defaultLdifFileIsSuccessful() {
|
public void defaultLdifFileIsSuccessful() {
|
||||||
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server/>");
|
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server/>");
|
||||||
ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class);
|
UnboundIdContainer dsContainer = this.appCtx.getBean(UnboundIdContainer.class);
|
||||||
|
|
||||||
assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif");
|
assertThat(ReflectionTestUtils.getField(dsContainer, "ldif")).isEqualTo("classpath*:*.ldif");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getDefaultPort() throws IOException {
|
private int getDefaultPort() throws IOException {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
|
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
|
||||||
|
|
||||||
<logger name="org.apache.directory" level="ERROR"/>
|
|
||||||
<logger name="JdbmTable" level="INFO"/>
|
<logger name="JdbmTable" level="INFO"/>
|
||||||
<logger name="JdbmIndex" level="INFO"/>
|
<logger name="JdbmIndex" level="INFO"/>
|
||||||
<logger name="org.apache.mina" level="WARN"/>
|
<logger name="org.apache.mina" level="WARN"/>
|
||||||
|
|
|
@ -54,8 +54,6 @@ public abstract class BeanIds {
|
||||||
|
|
||||||
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
|
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
|
||||||
|
|
||||||
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
|
|
||||||
|
|
||||||
public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer";
|
public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer";
|
||||||
|
|
||||||
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
|
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
|
||||||
|
|
|
@ -96,7 +96,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||||
pc.getReaderContext()
|
pc.getReaderContext()
|
||||||
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
|
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
|
||||||
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
|
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
|
||||||
+ "with Spring Security 6.5. Please update your schema declarations to the 6.5 schema.",
|
+ "with Spring Security 7.0. Please update your schema declarations to the 7.0 schema.",
|
||||||
element);
|
element);
|
||||||
}
|
}
|
||||||
String name = pc.getDelegate().getLocalName(element);
|
String name = pc.getDelegate().getLocalName(element);
|
||||||
|
@ -221,7 +221,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||||
|
|
||||||
private boolean matchesVersionInternal(Element element) {
|
private boolean matchesVersionInternal(Element element) {
|
||||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||||
return schemaLocation.matches("(?m).*spring-security-6\\.5.*.xsd.*")
|
return schemaLocation.matches("(?m).*spring-security-7\\.0.*.xsd.*")
|
||||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,17 +50,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
|
||||||
public void configure(B builder) throws Exception {
|
public void configure(B builder) throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}.
|
|
||||||
* This is useful for method chaining.
|
|
||||||
* @return the {@link SecurityBuilder} for further customizations
|
|
||||||
* @deprecated For removal in 7.0. Use the lambda based configuration instead.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public B and() {
|
|
||||||
return getBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link SecurityBuilder}. Cannot be null.
|
* Gets the {@link SecurityBuilder}. Cannot be null.
|
||||||
* @return the {@link SecurityBuilder}
|
* @return the {@link SecurityBuilder}
|
||||||
|
|
|
@ -67,9 +67,7 @@ public class AuthenticationManagerBuilder
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @param objectPostProcessor the
|
* @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
|
||||||
* {@link org.springframework.security.config.annotation.ObjectPostProcessor} instance
|
|
||||||
* to use.
|
|
||||||
*/
|
*/
|
||||||
public AuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
public AuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||||
super(objectPostProcessor, true);
|
super(objectPostProcessor, true);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
import org.springframework.security.config.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer;
|
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||||
|
@ -38,7 +37,6 @@ import org.springframework.security.ldap.authentication.LdapAuthenticator;
|
||||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
||||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||||
import org.springframework.security.ldap.search.LdapUserSearch;
|
import org.springframework.security.ldap.search.LdapUserSearch;
|
||||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
|
||||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||||
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
||||||
|
@ -61,12 +59,8 @@ import org.springframework.util.ClassUtils;
|
||||||
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
|
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
|
||||||
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
|
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
|
||||||
|
|
||||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
|
||||||
|
|
||||||
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||||
|
|
||||||
private static final boolean apacheDsPresent;
|
|
||||||
|
|
||||||
private static final boolean unboundIdPresent;
|
private static final boolean unboundIdPresent;
|
||||||
|
|
||||||
private String groupRoleAttribute = "cn";
|
private String groupRoleAttribute = "cn";
|
||||||
|
@ -101,7 +95,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ClassLoader classLoader = LdapAuthenticationProviderConfigurer.class.getClassLoader();
|
ClassLoader classLoader = LdapAuthenticationProviderConfigurer.class.getClassLoader();
|
||||||
apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
|
|
||||||
unboundIdPresent = ClassUtils.isPresent(UNBOUNDID_CLASSNAME, classLoader);
|
unboundIdPresent = ClassUtils.isPresent(UNBOUNDID_CLASSNAME, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +126,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||||
/**
|
/**
|
||||||
* Adds an {@link ObjectPostProcessor} for this class.
|
* Adds an {@link ObjectPostProcessor} for this class.
|
||||||
* @param objectPostProcessor
|
* @param objectPostProcessor
|
||||||
* @return the {@link ChannelSecurityConfigurer} for further customizations
|
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
|
||||||
*/
|
*/
|
||||||
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
||||||
addObjectPostProcessor(objectPostProcessor);
|
addObjectPostProcessor(objectPostProcessor);
|
||||||
|
@ -393,6 +386,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public B and() {
|
||||||
|
return getBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(B builder) throws Exception {
|
public void configure(B builder) throws Exception {
|
||||||
LdapAuthenticationProvider provider = postProcess(build());
|
LdapAuthenticationProvider provider = postProcess(build());
|
||||||
|
@ -468,8 +465,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||||
*/
|
*/
|
||||||
public final class ContextSourceBuilder {
|
public final class ContextSourceBuilder {
|
||||||
|
|
||||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
|
||||||
|
|
||||||
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||||
|
|
||||||
private static final int DEFAULT_PORT = 33389;
|
private static final int DEFAULT_PORT = 33389;
|
||||||
|
@ -585,14 +580,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||||
return contextSource;
|
return contextSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startEmbeddedLdapServer() throws Exception {
|
private void startEmbeddedLdapServer() {
|
||||||
if (apacheDsPresent) {
|
if (unboundIdPresent) {
|
||||||
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(this.root, this.ldif);
|
|
||||||
apacheDsContainer.setPort(getPort());
|
|
||||||
postProcess(apacheDsContainer);
|
|
||||||
this.port = apacheDsContainer.getLocalPort();
|
|
||||||
}
|
|
||||||
else if (unboundIdPresent) {
|
|
||||||
UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
|
UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
|
||||||
unboundIdContainer.setPort(getPort());
|
unboundIdContainer.setPort(getPort());
|
||||||
postProcess(unboundIdContainer);
|
postProcess(unboundIdContainer);
|
||||||
|
|
|
@ -41,4 +41,8 @@ public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuild
|
||||||
super(new InMemoryUserDetailsManager(new ArrayList<>()));
|
super(new InMemoryUserDetailsManager(new ArrayList<>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public B and() {
|
||||||
|
return getBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ import org.springframework.security.aot.hint.SecurityHintsRegistrar;
|
||||||
import org.springframework.security.authorization.AuthorizationProxyFactory;
|
import org.springframework.security.authorization.AuthorizationProxyFactory;
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
||||||
|
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor;
|
||||||
import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor;
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
|
|
||||||
|
@ -40,21 +42,23 @@ final class AuthorizationProxyConfiguration implements AopInfrastructureBean {
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
static AuthorizationAdvisorProxyFactory authorizationProxyFactory(
|
static AuthorizationAdvisorProxyFactory authorizationProxyFactory(
|
||||||
|
ObjectProvider<AuthorizationAdvisor> authorizationAdvisors, ObjectProvider<TargetVisitor> targetVisitors,
|
||||||
ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) {
|
ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) {
|
||||||
AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(new ArrayList<>());
|
List<AuthorizationAdvisor> advisors = new ArrayList<>();
|
||||||
|
authorizationAdvisors.forEach(advisors::add);
|
||||||
|
List<TargetVisitor> visitors = new ArrayList<>();
|
||||||
|
targetVisitors.orderedStream().forEach(visitors::add);
|
||||||
|
visitors.add(TargetVisitor.defaults());
|
||||||
|
AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(advisors);
|
||||||
|
factory.setTargetVisitor(TargetVisitor.of(visitors.toArray(TargetVisitor[]::new)));
|
||||||
customizers.forEach((c) -> c.customize(factory));
|
customizers.forEach((c) -> c.customize(factory));
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
static MethodInterceptor authorizeReturnObjectMethodInterceptor(ObjectProvider<AuthorizationAdvisor> provider,
|
static MethodInterceptor authorizeReturnObjectMethodInterceptor() {
|
||||||
AuthorizationAdvisorProxyFactory authorizationProxyFactory) {
|
return new AuthorizeReturnObjectMethodInterceptor();
|
||||||
provider.forEach(authorizationProxyFactory::addAdvisor);
|
|
||||||
AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor(
|
|
||||||
authorizationProxyFactory);
|
|
||||||
authorizationProxyFactory.addAdvisor(interceptor);
|
|
||||||
return interceptor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,13 +16,22 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Role;
|
import org.springframework.context.annotation.Role;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
|
import org.springframework.data.domain.SliceImpl;
|
||||||
|
import org.springframework.data.geo.GeoPage;
|
||||||
|
import org.springframework.data.geo.GeoResult;
|
||||||
|
import org.springframework.data.geo.GeoResults;
|
||||||
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
|
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
|
||||||
import org.springframework.security.authorization.AuthorizationProxyFactory;
|
import org.springframework.security.authorization.AuthorizationProxyFactory;
|
||||||
|
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
||||||
import org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar;
|
import org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar;
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ -34,4 +43,45 @@ final class AuthorizationProxyDataConfiguration implements AopInfrastructureBean
|
||||||
return new AuthorizeReturnObjectDataHintsRegistrar(proxyFactory);
|
return new AuthorizeReturnObjectDataHintsRegistrar(proxyFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
DataTargetVisitor dataTargetVisitor() {
|
||||||
|
return new DataTargetVisitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DataTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered {
|
||||||
|
|
||||||
|
private static final int DEFAULT_ORDER = 200;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
|
||||||
|
if (target instanceof GeoResults<?> geoResults) {
|
||||||
|
return new GeoResults<>(proxyFactory.proxy(geoResults.getContent()), geoResults.getAverageDistance());
|
||||||
|
}
|
||||||
|
if (target instanceof GeoResult<?> geoResult) {
|
||||||
|
return new GeoResult<>(proxyFactory.proxy(geoResult.getContent()), geoResult.getDistance());
|
||||||
|
}
|
||||||
|
if (target instanceof GeoPage<?> geoPage) {
|
||||||
|
GeoResults<?> results = new GeoResults<>(proxyFactory.proxy(geoPage.getContent()),
|
||||||
|
geoPage.getAverageDistance());
|
||||||
|
return new GeoPage<>(results, geoPage.getPageable(), geoPage.getTotalElements());
|
||||||
|
}
|
||||||
|
if (target instanceof PageImpl<?> page) {
|
||||||
|
List<?> content = proxyFactory.proxy(page.getContent());
|
||||||
|
return new PageImpl<>(content, page.getPageable(), page.getTotalElements());
|
||||||
|
}
|
||||||
|
if (target instanceof SliceImpl<?> slice) {
|
||||||
|
List<?> content = proxyFactory.proxy(slice.getContent());
|
||||||
|
return new SliceImpl<>(content, slice.getPageable(), slice.hasNext());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return DEFAULT_ORDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Role;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
||||||
|
import org.springframework.security.web.util.ThrowableAnalyzer;
|
||||||
|
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import org.springframework.web.servlet.View;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class AuthorizationProxyWebConfiguration implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
AuthorizationAdvisorProxyFactory.TargetVisitor webTargetVisitor() {
|
||||||
|
return new WebTargetVisitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
|
||||||
|
for (int i = 0; i < resolvers.size(); i++) {
|
||||||
|
HandlerExceptionResolver resolver = resolvers.get(i);
|
||||||
|
if (resolver instanceof DefaultHandlerExceptionResolver) {
|
||||||
|
resolvers.add(i, new AccessDeniedExceptionResolver());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolvers.add(new AccessDeniedExceptionResolver());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered {
|
||||||
|
|
||||||
|
private static final int DEFAULT_ORDER = 100;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
|
||||||
|
if (target instanceof ResponseEntity<?> entity) {
|
||||||
|
return new ResponseEntity<>(proxyFactory.proxy(entity.getBody()), entity.getHeaders(),
|
||||||
|
entity.getStatusCode());
|
||||||
|
}
|
||||||
|
if (target instanceof HttpEntity<?> entity) {
|
||||||
|
return new HttpEntity<>(proxyFactory.proxy(entity.getBody()), entity.getHeaders());
|
||||||
|
}
|
||||||
|
if (target instanceof ModelAndView mav) {
|
||||||
|
View view = mav.getView();
|
||||||
|
String viewName = mav.getViewName();
|
||||||
|
Map<String, Object> model = proxyFactory.proxy(mav.getModel());
|
||||||
|
ModelAndView proxied = (view != null) ? new ModelAndView(view, model)
|
||||||
|
: new ModelAndView(viewName, model);
|
||||||
|
proxied.setStatus(mav.getStatus());
|
||||||
|
return proxied;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return DEFAULT_ORDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AccessDeniedExceptionResolver implements HandlerExceptionResolver {
|
||||||
|
|
||||||
|
final ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||||
|
Exception ex) {
|
||||||
|
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);
|
||||||
|
Throwable accessDeniedException = this.throwableAnalyzer
|
||||||
|
.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
|
||||||
|
if (accessDeniedException != null) {
|
||||||
|
return new ModelAndView((model, req, res) -> {
|
||||||
|
throw ex;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2022 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.AuthorizationResult;
|
|
||||||
import org.springframework.security.authorization.ObservationAuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler;
|
|
||||||
import org.springframework.security.authorization.method.MethodInvocationResult;
|
|
||||||
import org.springframework.security.authorization.method.ThrowingMethodAuthorizationDeniedHandler;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.util.function.SingletonSupplier;
|
|
||||||
|
|
||||||
final class DeferringObservationAuthorizationManager<T>
|
|
||||||
implements AuthorizationManager<T>, MethodAuthorizationDeniedHandler {
|
|
||||||
|
|
||||||
private final Supplier<AuthorizationManager<T>> delegate;
|
|
||||||
|
|
||||||
private MethodAuthorizationDeniedHandler handler = new ThrowingMethodAuthorizationDeniedHandler();
|
|
||||||
|
|
||||||
DeferringObservationAuthorizationManager(ObjectProvider<ObservationRegistry> provider,
|
|
||||||
AuthorizationManager<T> delegate) {
|
|
||||||
this.delegate = SingletonSupplier.of(() -> {
|
|
||||||
ObservationRegistry registry = provider.getIfAvailable(() -> ObservationRegistry.NOOP);
|
|
||||||
if (registry.isNoop()) {
|
|
||||||
return delegate;
|
|
||||||
}
|
|
||||||
return new ObservationAuthorizationManager<>(registry, delegate);
|
|
||||||
});
|
|
||||||
if (delegate instanceof MethodAuthorizationDeniedHandler h) {
|
|
||||||
this.handler = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
|
|
||||||
return this.delegate.get().check(authentication, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) {
|
|
||||||
return this.handler.handleDeniedInvocation(methodInvocation, authorizationResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object handleDeniedInvocationResult(MethodInvocationResult methodInvocationResult,
|
|
||||||
AuthorizationResult authorizationResult) {
|
|
||||||
return this.handler.handleDeniedInvocationResult(methodInvocationResult, authorizationResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2023 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
|
||||||
import org.springframework.security.authorization.AuthorizationResult;
|
|
||||||
import org.springframework.security.authorization.ObservationReactiveAuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler;
|
|
||||||
import org.springframework.security.authorization.method.MethodInvocationResult;
|
|
||||||
import org.springframework.security.authorization.method.ThrowingMethodAuthorizationDeniedHandler;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.util.function.SingletonSupplier;
|
|
||||||
|
|
||||||
final class DeferringObservationReactiveAuthorizationManager<T>
|
|
||||||
implements ReactiveAuthorizationManager<T>, MethodAuthorizationDeniedHandler {
|
|
||||||
|
|
||||||
private final Supplier<ReactiveAuthorizationManager<T>> delegate;
|
|
||||||
|
|
||||||
private MethodAuthorizationDeniedHandler handler = new ThrowingMethodAuthorizationDeniedHandler();
|
|
||||||
|
|
||||||
DeferringObservationReactiveAuthorizationManager(ObjectProvider<ObservationRegistry> provider,
|
|
||||||
ReactiveAuthorizationManager<T> delegate) {
|
|
||||||
this.delegate = SingletonSupplier.of(() -> {
|
|
||||||
ObservationRegistry registry = provider.getIfAvailable(() -> ObservationRegistry.NOOP);
|
|
||||||
if (registry.isNoop()) {
|
|
||||||
return delegate;
|
|
||||||
}
|
|
||||||
return new ObservationReactiveAuthorizationManager<>(registry, delegate);
|
|
||||||
});
|
|
||||||
if (delegate instanceof MethodAuthorizationDeniedHandler h) {
|
|
||||||
this.handler = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
|
|
||||||
return this.delegate.get().check(authentication, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) {
|
|
||||||
return this.handler.handleDeniedInvocation(methodInvocation, authorizationResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object handleDeniedInvocationResult(MethodInvocationResult methodInvocationResult,
|
|
||||||
AuthorizationResult authorizationResult) {
|
|
||||||
return this.handler.handleDeniedInvocationResult(methodInvocationResult, authorizationResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -41,6 +41,9 @@ final class MethodSecuritySelector implements ImportSelector {
|
||||||
private static final boolean isDataPresent = ClassUtils
|
private static final boolean isDataPresent = ClassUtils
|
||||||
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
||||||
|
|
||||||
|
private static final boolean isWebPresent = ClassUtils
|
||||||
|
.isPresent("org.springframework.web.servlet.DispatcherServlet", null);
|
||||||
|
|
||||||
private static final boolean isObservabilityPresent = ClassUtils
|
private static final boolean isObservabilityPresent = ClassUtils
|
||||||
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
||||||
|
|
||||||
|
@ -67,6 +70,9 @@ final class MethodSecuritySelector implements ImportSelector {
|
||||||
if (isDataPresent) {
|
if (isDataPresent) {
|
||||||
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
|
if (isWebPresent) {
|
||||||
|
imports.add(AuthorizationProxyWebConfiguration.class.getName());
|
||||||
|
}
|
||||||
if (isObservabilityPresent) {
|
if (isObservabilityPresent) {
|
||||||
imports.add(MethodObservationConfiguration.class.getName());
|
imports.add(MethodObservationConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -83,10 +83,11 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration
|
||||||
|
|
||||||
private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
|
private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
|
||||||
|
|
||||||
@Autowired(required = false)
|
ReactiveAuthorizationManagerMethodSecurityConfiguration(
|
||||||
ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler,
|
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlers,
|
||||||
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocation>>> preAuthorizePostProcessor,
|
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocation>>> preAuthorizePostProcessor,
|
||||||
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocationResult>>> postAuthorizePostProcessor) {
|
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocationResult>>> postAuthorizePostProcessor) {
|
||||||
|
MethodSecurityExpressionHandler expressionHandler = expressionHandlers.getIfUnique();
|
||||||
if (expressionHandler != null) {
|
if (expressionHandler != null) {
|
||||||
this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
||||||
this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler);
|
this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -38,6 +38,9 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
|
||||||
private static final boolean isDataPresent = ClassUtils
|
private static final boolean isDataPresent = ClassUtils
|
||||||
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
||||||
|
|
||||||
|
private static final boolean isWebPresent = ClassUtils.isPresent("org.springframework.web.server.ServerWebExchange",
|
||||||
|
null);
|
||||||
|
|
||||||
private static final boolean isObservabilityPresent = ClassUtils
|
private static final boolean isObservabilityPresent = ClassUtils
|
||||||
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
||||||
|
|
||||||
|
@ -61,6 +64,9 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
|
||||||
if (isDataPresent) {
|
if (isDataPresent) {
|
||||||
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
|
if (isWebPresent) {
|
||||||
|
imports.add(AuthorizationProxyWebConfiguration.class.getName());
|
||||||
|
}
|
||||||
if (isObservabilityPresent) {
|
if (isObservabilityPresent) {
|
||||||
imports.add(ReactiveMethodObservationConfiguration.class.getName());
|
imports.add(ReactiveMethodObservationConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,16 @@ public enum PayloadInterceptorOrder implements Ordered {
|
||||||
/**
|
/**
|
||||||
* Where basic authentication is placed.
|
* Where basic authentication is placed.
|
||||||
* @see RSocketSecurity#basicAuthentication(Customizer)
|
* @see RSocketSecurity#basicAuthentication(Customizer)
|
||||||
|
* @deprecated please see {@link PayloadInterceptorOrder#AUTHENTICATION}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
BASIC_AUTHENTICATION,
|
BASIC_AUTHENTICATION,
|
||||||
/**
|
/**
|
||||||
* Where JWT based authentication is performed.
|
* Where JWT based authentication is performed.
|
||||||
* @see RSocketSecurity#jwt(Customizer)
|
* @see RSocketSecurity#jwt(Customizer)
|
||||||
|
* @deprecated please see {@link PayloadInterceptorOrder#AUTHENTICATION}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
JWT_AUTHENTICATION,
|
JWT_AUTHENTICATION,
|
||||||
/**
|
/**
|
||||||
* A generic placeholder for other types of authentication.
|
* A generic placeholder for other types of authentication.
|
||||||
|
|
|
@ -41,7 +41,6 @@ import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
import org.springframework.security.config.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping;
|
import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry;
|
|
||||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||||
|
@ -170,7 +169,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associates a list of {@link RequestMatcher} instances with the
|
* Associates a list of {@link RequestMatcher} instances with the
|
||||||
* {@link AbstractConfigAttributeRequestMatcherRegistry}
|
* {@link AbstractRequestMatcherRegistry}
|
||||||
* @param requestMatchers the {@link RequestMatcher} instances
|
* @param requestMatchers the {@link RequestMatcher} instances
|
||||||
* @return the object that is chained after creating the {@link RequestMatcher}
|
* @return the object that is chained after creating the {@link RequestMatcher}
|
||||||
*/
|
*/
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,7 +35,9 @@ import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.security.access.PermissionEvaluator;
|
import org.springframework.security.access.PermissionEvaluator;
|
||||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.SingleResultAuthorizationManager;
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
import org.springframework.security.config.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||||
|
@ -58,6 +60,8 @@ import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||||
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
||||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||||
|
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||||
|
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
||||||
import org.springframework.security.web.debug.DebugFilter;
|
import org.springframework.security.web.debug.DebugFilter;
|
||||||
import org.springframework.security.web.firewall.CompositeRequestRejectedHandler;
|
import org.springframework.security.web.firewall.CompositeRequestRejectedHandler;
|
||||||
import org.springframework.security.web.firewall.HttpFirewall;
|
import org.springframework.security.web.firewall.HttpFirewall;
|
||||||
|
@ -65,6 +69,7 @@ import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandle
|
||||||
import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler;
|
import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler;
|
||||||
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||||
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||||
|
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -230,8 +235,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not
|
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not
|
||||||
* specified, then a {@link RequestMatcherDelegatingWebInvocationPrivilegeEvaluator}
|
* specified, then a {@link AuthorizationManagerWebInvocationPrivilegeEvaluator} will
|
||||||
* will be created based on the list of {@link SecurityFilterChain}.
|
* be created based on the list of {@link SecurityFilterChain}.
|
||||||
* @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use
|
* @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use
|
||||||
* @return the {@link WebSecurity} for further customizations
|
* @return the {@link WebSecurity} for further customizations
|
||||||
*/
|
*/
|
||||||
|
@ -300,24 +305,33 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||||
+ ".addSecurityFilterChainBuilder directly");
|
+ ".addSecurityFilterChainBuilder directly");
|
||||||
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
|
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
|
||||||
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
|
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
|
||||||
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
|
RequestMatcherDelegatingAuthorizationManager.Builder builder = RequestMatcherDelegatingAuthorizationManager
|
||||||
|
.builder();
|
||||||
|
boolean mappings = false;
|
||||||
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
|
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
|
||||||
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
|
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
|
||||||
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
|
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
|
||||||
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
|
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
|
||||||
securityFilterChains.add(securityFilterChain);
|
securityFilterChains.add(securityFilterChain);
|
||||||
requestMatcherPrivilegeEvaluatorsEntries
|
builder.add(ignoredRequest, SingleResultAuthorizationManager.permitAll());
|
||||||
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
|
mappings = true;
|
||||||
}
|
}
|
||||||
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
|
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
|
||||||
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
|
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
|
||||||
securityFilterChains.add(securityFilterChain);
|
securityFilterChains.add(securityFilterChain);
|
||||||
requestMatcherPrivilegeEvaluatorsEntries
|
mappings = addAuthorizationManager(securityFilterChain, builder) || mappings;
|
||||||
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
|
|
||||||
}
|
}
|
||||||
if (this.privilegeEvaluator == null) {
|
if (this.privilegeEvaluator == null) {
|
||||||
|
AuthorizationManager<HttpServletRequest> authorizationManager = mappings ? builder.build()
|
||||||
|
: SingleResultAuthorizationManager.permitAll();
|
||||||
|
AuthorizationManagerWebInvocationPrivilegeEvaluator privilegeEvaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
|
||||||
|
authorizationManager);
|
||||||
|
privilegeEvaluator.setServletContext(this.servletContext);
|
||||||
|
if (this.privilegeEvaluatorRequestTransformer != null) {
|
||||||
|
privilegeEvaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer);
|
||||||
|
}
|
||||||
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
|
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
|
||||||
requestMatcherPrivilegeEvaluatorsEntries);
|
List.of(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE, List.of(privilegeEvaluator))));
|
||||||
}
|
}
|
||||||
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
|
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
|
||||||
if (this.httpFirewall != null) {
|
if (this.httpFirewall != null) {
|
||||||
|
@ -350,30 +364,33 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> getRequestMatcherPrivilegeEvaluatorsEntry(
|
private boolean addAuthorizationManager(SecurityFilterChain securityFilterChain,
|
||||||
SecurityFilterChain securityFilterChain) {
|
RequestMatcherDelegatingAuthorizationManager.Builder builder) {
|
||||||
List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = new ArrayList<>();
|
boolean mappings = false;
|
||||||
for (Filter filter : securityFilterChain.getFilters()) {
|
for (Filter filter : securityFilterChain.getFilters()) {
|
||||||
if (filter instanceof FilterSecurityInterceptor) {
|
if (filter instanceof FilterSecurityInterceptor securityInterceptor) {
|
||||||
DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
|
DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
|
||||||
(FilterSecurityInterceptor) filter);
|
securityInterceptor);
|
||||||
defaultWebInvocationPrivilegeEvaluator.setServletContext(this.servletContext);
|
privilegeEvaluator.setServletContext(this.servletContext);
|
||||||
privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator);
|
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, context) -> {
|
||||||
|
HttpServletRequest request = context.getRequest();
|
||||||
|
boolean result = privilegeEvaluator.isAllowed(request.getContextPath(), request.getRequestURI(),
|
||||||
|
request.getMethod(), authentication.get());
|
||||||
|
return new AuthorizationDecision(result);
|
||||||
|
};
|
||||||
|
builder.add(securityFilterChain::matches, authorizationManager);
|
||||||
|
mappings = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (filter instanceof AuthorizationFilter) {
|
if (filter instanceof AuthorizationFilter authorization) {
|
||||||
AuthorizationManager<HttpServletRequest> authorizationManager = ((AuthorizationFilter) filter)
|
AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager();
|
||||||
.getAuthorizationManager();
|
builder.add(securityFilterChain::matches,
|
||||||
AuthorizationManagerWebInvocationPrivilegeEvaluator evaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
|
(authentication, context) -> (AuthorizationDecision) authorizationManager
|
||||||
authorizationManager);
|
.authorize(authentication, context.getRequest()));
|
||||||
evaluator.setServletContext(this.servletContext);
|
mappings = true;
|
||||||
if (this.privilegeEvaluatorRequestTransformer != null) {
|
|
||||||
evaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer);
|
|
||||||
}
|
|
||||||
privilegeEvaluators.add(evaluator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);
|
return mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -46,8 +46,9 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||||
*
|
*
|
||||||
* @Bean
|
* @Bean
|
||||||
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
* http.authorizeHttpRequests().requestMatchers("/public/**").permitAll().anyRequest()
|
* http.authorizeHttpRequests((authorize) -> authorize
|
||||||
* .hasRole("USER").and()
|
* .requestMatchers("/public/**").permitAll()
|
||||||
|
* .anyRequest().hasRole("USER"))
|
||||||
* // Possibly more configuration ...
|
* // Possibly more configuration ...
|
||||||
* .formLogin() // enable form based log in
|
* .formLogin() // enable form based log in
|
||||||
* // set permitAll for all URLs associated with Form Login
|
* // set permitAll for all URLs associated with Form Login
|
||||||
|
|
|
@ -78,6 +78,8 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
|
||||||
|
|
||||||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||||
|
|
||||||
|
private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer";
|
||||||
|
|
||||||
private BeanResolver beanResolver;
|
private BeanResolver beanResolver;
|
||||||
|
|
||||||
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
||||||
|
@ -119,17 +121,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to ensure Spring MVC request matching is cached.
|
|
||||||
*
|
|
||||||
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
|
|
||||||
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
|
|
||||||
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
|
|
||||||
* and then adds a {@link CompositeFilter} that contains
|
|
||||||
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
|
|
||||||
* FilterChainProxy under the original Bean name.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Bean
|
@Bean
|
||||||
static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() {
|
static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() {
|
||||||
return new BeanDefinitionRegistryPostProcessor() {
|
return new BeanDefinitionRegistryPostProcessor() {
|
||||||
|
@ -144,12 +135,15 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
|
||||||
}
|
}
|
||||||
|
|
||||||
String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer";
|
String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer";
|
||||||
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
|
if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME)
|
||||||
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
|
&& !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
|
||||||
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
|
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
|
||||||
.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)
|
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
|
||||||
.getBeanDefinition();
|
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
|
||||||
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
|
.addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)
|
||||||
|
.getBeanDefinition();
|
||||||
|
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinition filterChainProxy = registry
|
BeanDefinition filterChainProxy = registry
|
||||||
|
@ -178,7 +172,11 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
|
||||||
/**
|
/**
|
||||||
* {@link FactoryBean} to defer creation of
|
* {@link FactoryBean} to defer creation of
|
||||||
* {@link HandlerMappingIntrospector#createCacheFilter()}
|
* {@link HandlerMappingIntrospector#createCacheFilter()}
|
||||||
|
*
|
||||||
|
* @deprecated see {@link WebSecurityConfiguration} for
|
||||||
|
* {@link org.springframework.web.util.pattern.PathPattern} replacement
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
static class HandlerMappingIntrospectorCacheFilterFactoryBean
|
static class HandlerMappingIntrospectorCacheFilterFactoryBean
|
||||||
implements ApplicationContextAware, FactoryBean<Filter> {
|
implements ApplicationContextAware, FactoryBean<Filter> {
|
||||||
|
|
||||||
|
@ -207,7 +205,11 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
|
||||||
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
|
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
|
||||||
* delegates to {@link CompositeFilter} for
|
* delegates to {@link CompositeFilter} for
|
||||||
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
|
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
|
||||||
|
*
|
||||||
|
* @deprecated see {@link WebSecurityConfiguration} for
|
||||||
|
* {@link org.springframework.web.util.pattern.PathPattern} replacement
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
static class CompositeFilterChainProxy extends FilterChainProxy {
|
static class CompositeFilterChainProxy extends FilterChainProxy {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,16 +16,29 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.web.configuration;
|
package org.springframework.security.config.annotation.web.configuration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import jakarta.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeanMetadataElement;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||||
|
import org.springframework.beans.factory.support.ManagedList;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.DependsOn;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
@ -45,11 +58,18 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
||||||
import org.springframework.security.context.DelegatingApplicationListener;
|
import org.springframework.security.context.DelegatingApplicationListener;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.web.FilterChainProxy;
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
import org.springframework.security.web.FilterInvocation;
|
import org.springframework.security.web.FilterInvocation;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||||
|
import org.springframework.security.web.debug.DebugFilter;
|
||||||
|
import org.springframework.security.web.firewall.HttpFirewall;
|
||||||
|
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||||
|
import org.springframework.web.filter.CompositeFilter;
|
||||||
|
import org.springframework.web.filter.ServletRequestPathFilter;
|
||||||
|
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
|
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
|
||||||
|
@ -186,6 +206,51 @@ public class WebSecurityConfiguration implements ImportAware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to ensure Spring MVC request matching is cached.
|
||||||
|
*
|
||||||
|
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
|
||||||
|
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
|
||||||
|
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
|
||||||
|
* and then adds a {@link CompositeFilter} that contains
|
||||||
|
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
|
||||||
|
* FilterChainProxy under the original Bean name.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
static BeanDefinitionRegistryPostProcessor springSecurityPathPatternParserBeanDefinitionRegistryPostProcessor() {
|
||||||
|
return new BeanDefinitionRegistryPostProcessor() {
|
||||||
|
@Override
|
||||||
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||||
|
BeanDefinition filterChainProxy = registry
|
||||||
|
.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
|
||||||
|
|
||||||
|
if (filterChainProxy.getResolvableType().isInstance(CompositeFilterChainProxy.class)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeanDefinitionBuilder pppCacheFilterBldr = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(ServletRequestPathFilter.class)
|
||||||
|
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
|
||||||
|
ManagedList<BeanMetadataElement> filters = new ManagedList<>();
|
||||||
|
filters.add(pppCacheFilterBldr.getBeanDefinition());
|
||||||
|
filters.add(filterChainProxy);
|
||||||
|
BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(CompositeFilterChainProxy.class)
|
||||||
|
.addConstructorArgValue(filters);
|
||||||
|
|
||||||
|
registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
|
||||||
|
registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
|
||||||
|
compositeSpringSecurityFilterChainBldr.getBeanDefinition());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom version of the Spring provided AnnotationAwareOrderComparator that uses
|
* A custom version of the Spring provided AnnotationAwareOrderComparator that uses
|
||||||
* {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class
|
* {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class
|
||||||
|
@ -219,4 +284,121 @@ public class WebSecurityConfiguration implements ImportAware {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
|
||||||
|
* delegates to {@link CompositeFilter} for
|
||||||
|
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
|
||||||
|
*/
|
||||||
|
static class CompositeFilterChainProxy extends FilterChainProxy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}
|
||||||
|
*/
|
||||||
|
private final Filter doFilterDelegate;
|
||||||
|
|
||||||
|
private final FilterChainProxy springSecurityFilterChain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
* @param filters the Filters to delegate to. One of which must be
|
||||||
|
* FilterChainProxy.
|
||||||
|
*/
|
||||||
|
CompositeFilterChainProxy(List<? extends Filter> filters) {
|
||||||
|
this.doFilterDelegate = createDoFilterDelegate(filters);
|
||||||
|
this.springSecurityFilterChain = findFilterChainProxy(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
this.springSecurityFilterChain.afterPropertiesSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
this.doFilterDelegate.doFilter(request, response, chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Filter> getFilters(String url) {
|
||||||
|
return this.springSecurityFilterChain.getFilters(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SecurityFilterChain> getFilterChains() {
|
||||||
|
return this.springSecurityFilterChain.getFilterChains();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
||||||
|
this.springSecurityFilterChain.setSecurityContextHolderStrategy(securityContextHolderStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFilterChainValidator(FilterChainValidator filterChainValidator) {
|
||||||
|
this.springSecurityFilterChain.setFilterChainValidator(filterChainValidator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFilterChainDecorator(FilterChainDecorator filterChainDecorator) {
|
||||||
|
this.springSecurityFilterChain.setFilterChainDecorator(filterChainDecorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFirewall(HttpFirewall firewall) {
|
||||||
|
this.springSecurityFilterChain.setFirewall(firewall);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRequestRejectedHandler(RequestRejectedHandler requestRejectedHandler) {
|
||||||
|
this.springSecurityFilterChain.setRequestRejectedHandler(requestRejectedHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used through reflection by Spring Security's Test support to lookup the
|
||||||
|
* FilterChainProxy Filters for a specific HttpServletRequest.
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<? extends Filter> getFilters(HttpServletRequest request) {
|
||||||
|
List<SecurityFilterChain> filterChains = this.springSecurityFilterChain.getFilterChains();
|
||||||
|
for (SecurityFilterChain chain : filterChains) {
|
||||||
|
if (chain.matches(request)) {
|
||||||
|
return chain.getFilters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the Filter to delegate to for doFilter
|
||||||
|
* @param filters the Filters to delegate to.
|
||||||
|
* @return the Filter for doFilter
|
||||||
|
*/
|
||||||
|
private static Filter createDoFilterDelegate(List<? extends Filter> filters) {
|
||||||
|
CompositeFilter delegate = new CompositeFilter();
|
||||||
|
delegate.setFilters(filters);
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the FilterChainProxy in a List of Filter
|
||||||
|
* @param filters
|
||||||
|
* @return non-null FilterChainProxy
|
||||||
|
* @throws IllegalStateException if the FilterChainProxy cannot be found
|
||||||
|
*/
|
||||||
|
private static FilterChainProxy findFilterChainProxy(List<? extends Filter> filters) {
|
||||||
|
for (Filter filter : filters) {
|
||||||
|
if (filter instanceof FilterChainProxy fcp) {
|
||||||
|
return fcp;
|
||||||
|
}
|
||||||
|
if (filter instanceof DebugFilter debugFilter) {
|
||||||
|
return debugFilter.getFilterChainProxy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Couldn't find FilterChainProxy in " + filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.UUID;
|
||||||
|
|
||||||
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
@ -57,7 +58,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#anonymous()
|
* @see HttpSecurity#anonymous(Customizer)
|
||||||
*/
|
*/
|
||||||
public AnonymousConfigurer() {
|
public AnonymousConfigurer() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,17 +231,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the {@link HttpSecurityBuilder} when done using the
|
|
||||||
* {@link AuthorizeHttpRequestsConfigurer}. This is useful for method chaining.
|
|
||||||
* @return the {@link HttpSecurityBuilder} for further customizations
|
|
||||||
* @deprecated For removal in 7.0. Use the lambda based configuration instead.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public H and() {
|
|
||||||
return AuthorizeHttpRequestsConfigurer.this.and();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,10 +24,7 @@ import java.util.List;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.access.SecurityConfig;
|
import org.springframework.security.access.SecurityConfig;
|
||||||
import org.springframework.security.config.Customizer;
|
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
import org.springframework.security.config.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
|
||||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||||
|
@ -96,7 +93,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#requiresChannel()
|
* @see HttpSecurity#requiresChannel(Customizer)
|
||||||
*/
|
*/
|
||||||
public ChannelSecurityConfigurer(ApplicationContext context) {
|
public ChannelSecurityConfigurer(ApplicationContext context) {
|
||||||
this.REGISTRY = new ChannelRequestMatcherRegistry(context);
|
this.REGISTRY = new ChannelRequestMatcherRegistry(context);
|
||||||
|
@ -207,18 +204,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the {@link SecurityBuilder} when done using the
|
|
||||||
* {@link SecurityConfigurer}. This is useful for method chaining.
|
|
||||||
* @return the type of {@link HttpSecurityBuilder} that is being configured
|
|
||||||
* @deprecated For removal in 7.0. Use
|
|
||||||
* {@link HttpSecurity#requiresChannel(Customizer)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public H and() {
|
|
||||||
return ChannelSecurityConfigurer.this.and();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||||
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -57,7 +58,7 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
* @see HttpSecurity#cors()
|
* @see HttpSecurity#cors(Customizer)
|
||||||
*/
|
*/
|
||||||
public CorsConfigurer() {
|
public CorsConfigurer() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,12 +19,15 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
@ -34,13 +37,17 @@ import org.springframework.security.web.access.CompositeAccessDeniedHandler;
|
||||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||||
import org.springframework.security.web.access.ObservationMarkingAccessDeniedHandler;
|
import org.springframework.security.web.access.ObservationMarkingAccessDeniedHandler;
|
||||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
|
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
|
||||||
import org.springframework.security.web.csrf.CsrfFilter;
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
import org.springframework.security.web.csrf.CsrfLogoutHandler;
|
import org.springframework.security.web.csrf.CsrfLogoutHandler;
|
||||||
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
|
||||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||||
|
import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler;
|
||||||
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
|
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
|
||||||
import org.springframework.security.web.session.InvalidSessionStrategy;
|
import org.springframework.security.web.session.InvalidSessionStrategy;
|
||||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||||
|
@ -48,6 +55,7 @@ import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds
|
* Adds
|
||||||
|
@ -96,7 +104,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#csrf()
|
* @see HttpSecurity#csrf(Customizer)
|
||||||
*/
|
*/
|
||||||
public CsrfConfigurer(ApplicationContext context) {
|
public CsrfConfigurer(ApplicationContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -156,16 +164,16 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* http
|
* http
|
||||||
* .csrf()
|
* .csrf((csrf) -> csrf
|
||||||
* .ignoringRequestMatchers((request) -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With")))
|
* .ignoringRequestMatchers((request) -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With"))))
|
||||||
* .and()
|
|
||||||
* ...
|
* ...
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
*/
|
*/
|
||||||
public CsrfConfigurer<H> ignoringRequestMatchers(RequestMatcher... requestMatchers) {
|
public CsrfConfigurer<H> ignoringRequestMatchers(RequestMatcher... requestMatchers) {
|
||||||
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers).and();
|
new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,9 +192,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* http
|
* http
|
||||||
* .csrf()
|
* .csrf((csrf) -> csrf
|
||||||
* .ignoringRequestMatchers("/sockjs/**")
|
* .ignoringRequestMatchers("/sockjs/**"))
|
||||||
* .and()
|
|
||||||
* ...
|
* ...
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -194,7 +201,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @see AbstractRequestMatcherRegistry#requestMatchers(String...)
|
* @see AbstractRequestMatcherRegistry#requestMatchers(String...)
|
||||||
*/
|
*/
|
||||||
public CsrfConfigurer<H> ignoringRequestMatchers(String... patterns) {
|
public CsrfConfigurer<H> ignoringRequestMatchers(String... patterns) {
|
||||||
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns).and();
|
new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -214,6 +222,21 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Sensible CSRF defaults when used in combination with a single page application.
|
||||||
|
* Creates a cookie-based token repository and a custom request handler to resolve the
|
||||||
|
* actual token value instead of the encoded token.
|
||||||
|
* </p>
|
||||||
|
* @return the {@link CsrfConfigurer} for further customizations
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
public CsrfConfigurer<H> spa() {
|
||||||
|
this.csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||||
|
this.requestHandler = new SpaCsrfTokenRequestHandler();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void configure(H http) {
|
public void configure(H http) {
|
||||||
|
@ -363,10 +386,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
setApplicationContext(context);
|
setApplicationContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
CsrfConfigurer<H> and() {
|
|
||||||
return CsrfConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IgnoreCsrfProtectionRegistry chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
protected IgnoreCsrfProtectionRegistry chainRequestMatchers(List<RequestMatcher> requestMatchers) {
|
||||||
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(requestMatchers);
|
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(requestMatchers);
|
||||||
|
@ -375,4 +394,27 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler {
|
||||||
|
|
||||||
|
private final CsrfTokenRequestAttributeHandler plain = new CsrfTokenRequestAttributeHandler();
|
||||||
|
|
||||||
|
private final CsrfTokenRequestAttributeHandler xor = new XorCsrfTokenRequestAttributeHandler();
|
||||||
|
|
||||||
|
SpaCsrfTokenRequestHandler() {
|
||||||
|
this.xor.setCsrfRequestAttributeName(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
|
||||||
|
this.xor.handle(request, response, csrfToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
|
||||||
|
String headerValue = request.getHeader(csrfToken.getHeaderName());
|
||||||
|
return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,6 @@ import org.springframework.security.web.csrf.CsrfToken;
|
||||||
* Adds a Filter that will generate a login page if one is not specified otherwise when
|
* Adds a Filter that will generate a login page if one is not specified otherwise when
|
||||||
* using {@link EnableWebSecurity}.
|
* using {@link EnableWebSecurity}.
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* By default an
|
|
||||||
* {@link org.springframework.security.web.access.channel.InsecureChannelProcessor} and a
|
|
||||||
* {@link org.springframework.security.web.access.channel.SecureChannelProcessor} will be
|
|
||||||
* registered.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <h2>Security Filters</h2>
|
* <h2>Security Filters</h2>
|
||||||
*
|
*
|
||||||
* The following Filters are conditionally populated
|
* The following Filters are conditionally populated
|
||||||
|
@ -58,8 +51,6 @@ import org.springframework.security.web.csrf.CsrfToken;
|
||||||
* The following shared objects are used:
|
* The following shared objects are used:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link org.springframework.security.web.PortMapper} is used to create the default
|
|
||||||
* {@link org.springframework.security.web.access.channel.ChannelProcessor} instances</li>
|
|
||||||
* <li>{@link FormLoginConfigurer} is used to determine if the
|
* <li>{@link FormLoginConfigurer} is used to determine if the
|
||||||
* {@link DefaultLoginPageConfigurer} should be added and how to configure it.</li>
|
* {@link DefaultLoginPageConfigurer} should be added and how to configure it.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
@ -76,7 +77,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#exceptionHandling()
|
* @see HttpSecurity#exceptionHandling(Customizer)
|
||||||
*/
|
*/
|
||||||
public ExceptionHandlingConfigurer() {
|
public ExceptionHandlingConfigurer() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.springframework.security.access.SecurityConfig;
|
||||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
import org.springframework.security.config.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
@ -77,7 +78,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Yanming Zhou
|
* @author Yanming Zhou
|
||||||
* @author Ngoc Nhan
|
* @author Ngoc Nhan
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
|
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests(Customizer)
|
||||||
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
|
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -104,7 +105,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#authorizeRequests()
|
* @see HttpSecurity#authorizeRequests(Customizer)
|
||||||
*/
|
*/
|
||||||
public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
|
public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
|
||||||
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class)
|
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class)
|
||||||
|
@ -250,7 +251,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
|
||||||
}
|
}
|
||||||
|
|
||||||
public H and() {
|
public H and() {
|
||||||
return ExpressionUrlAuthorizationConfigurer.this.and();
|
return ExpressionUrlAuthorizationConfigurer.this.getBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.security.config.annotation.web.configurers;
|
package org.springframework.security.config.annotation.web.configurers;
|
||||||
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
@ -74,7 +75,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#formLogin()
|
* @see HttpSecurity#formLogin(Customizer)
|
||||||
*/
|
*/
|
||||||
public FormLoginConfigurer() {
|
public FormLoginConfigurer() {
|
||||||
super(new UsernamePasswordAuthenticationFilter(), null);
|
super(new UsernamePasswordAuthenticationFilter(), null);
|
||||||
|
|
|
@ -111,7 +111,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
* @see HttpSecurity#headers()
|
* @see HttpSecurity#headers(Customizer)
|
||||||
*/
|
*/
|
||||||
public HeadersConfigurer() {
|
public HeadersConfigurer() {
|
||||||
}
|
}
|
||||||
|
@ -127,26 +127,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
|
|
||||||
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
|
|
||||||
* >X-Content-Type-Options</a>:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* X-Content-Type-Options: nosniff
|
|
||||||
* </pre>
|
|
||||||
* @return the {@link ContentTypeOptionsConfig} for additional customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)} or
|
|
||||||
* {@code contentTypeOptions(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public ContentTypeOptionsConfig contentTypeOptions() {
|
|
||||||
return this.contentTypeOptions.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
|
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
|
||||||
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
|
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
|
||||||
|
@ -164,26 +144,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <strong>Note this is not comprehensive XSS protection!</strong>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
|
|
||||||
* "https://web.archive.org/web/20160201174302/https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
|
|
||||||
* >X-XSS-Protection header</a>
|
|
||||||
* </p>
|
|
||||||
* @return the {@link XXssConfig} for additional customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
|
||||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public XXssConfig xssProtection() {
|
|
||||||
return this.xssProtection.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <strong>Note this is not comprehensive XSS protection!</strong>
|
* <strong>Note this is not comprehensive XSS protection!</strong>
|
||||||
*
|
*
|
||||||
|
@ -201,26 +161,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
|
|
||||||
* following headers:
|
|
||||||
* <ul>
|
|
||||||
* <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
|
|
||||||
* <li>Pragma: no-cache</li>
|
|
||||||
* <li>Expires: 0</li>
|
|
||||||
* </ul>
|
|
||||||
* @return the {@link CacheControlConfig} for additional customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or
|
|
||||||
* {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public CacheControlConfig cacheControl() {
|
|
||||||
return this.cacheControl.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
|
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
|
||||||
* following headers:
|
* following headers:
|
||||||
|
@ -238,19 +178,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows customizing the {@link HstsHeaderWriter} which provides support for
|
|
||||||
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
|
|
||||||
* (HSTS)</a>.
|
|
||||||
* @return the {@link HstsConfig} for additional customizations
|
|
||||||
* @deprecated For removal in 7.0. Use
|
|
||||||
* {@link #httpStrictTransportSecurity(Customizer)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HstsConfig httpStrictTransportSecurity() {
|
|
||||||
return this.hsts.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows customizing the {@link HstsHeaderWriter} which provides support for
|
* Allows customizing the {@link HstsHeaderWriter} which provides support for
|
||||||
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
|
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
|
||||||
|
@ -264,20 +191,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
|
|
||||||
* @return the {@link FrameOptionsConfig} for additional customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
|
||||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public FrameOptionsConfig frameOptions() {
|
|
||||||
return this.frameOptions.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
|
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
|
||||||
* @param frameOptionsCustomizer the {@link Customizer} to provide more options for
|
* @param frameOptionsCustomizer the {@link Customizer} to provide more options for
|
||||||
|
@ -289,21 +202,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
|
|
||||||
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
|
|
||||||
* @return the {@link HpkpConfig} for additional customizations
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @deprecated see <a href=
|
|
||||||
* "https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate
|
|
||||||
* and Public Key Pinning</a> for more context
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public HpkpConfig httpPublicKeyPinning() {
|
|
||||||
return this.hpkp.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
|
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
|
||||||
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
|
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
|
||||||
|
@ -320,39 +218,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
|
|
||||||
* Policy (CSP) Level 2</a>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Calling this method automatically enables (includes) the Content-Security-Policy
|
|
||||||
* header in the response using the supplied security policy directive(s).
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which
|
|
||||||
* supports the writing of the two headers as detailed in the W3C Candidate
|
|
||||||
* Recommendation:
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li>Content-Security-Policy</li>
|
|
||||||
* <li>Content-Security-Policy-Report-Only</li>
|
|
||||||
* </ul>
|
|
||||||
* @return the {@link ContentSecurityPolicyConfig} for additional configuration
|
|
||||||
* @throws IllegalArgumentException if policyDirectives is null or empty
|
|
||||||
* @since 4.1
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
|
||||||
* instead
|
|
||||||
* @see ContentSecurityPolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) {
|
|
||||||
this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives);
|
|
||||||
return this.contentSecurityPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
|
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
|
||||||
|
@ -454,71 +319,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
|
||||||
* Policy</a>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
|
|
||||||
* the writing of the header as detailed in the W3C Technical Report:
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li>Referrer-Policy</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Default value is:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Referrer-Policy: no-referrer
|
|
||||||
* </pre>
|
|
||||||
* @return the {@link ReferrerPolicyConfig} for additional configuration
|
|
||||||
* @since 4.2
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
|
||||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
* @see ReferrerPolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public ReferrerPolicyConfig referrerPolicy() {
|
|
||||||
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
|
|
||||||
return this.referrerPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
|
||||||
* Policy</a>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
|
|
||||||
* the writing of the header as detailed in the W3C Technical Report:
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li>Referrer-Policy</li>
|
|
||||||
* </ul>
|
|
||||||
* @return the {@link ReferrerPolicyConfig} for additional configuration
|
|
||||||
* @throws IllegalArgumentException if policy is null or empty
|
|
||||||
* @since 4.2
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
|
||||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
* @see ReferrerPolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) {
|
|
||||||
this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy);
|
|
||||||
return this.referrerPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
|
||||||
|
@ -568,35 +368,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this.featurePolicy;
|
return this.featurePolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Allows configuration for
|
|
||||||
* <a href="https://w3c.github.io/webappsec-permissions-policy/">Permissions
|
|
||||||
* Policy</a>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link PermissionsPolicyHeaderWriter} which
|
|
||||||
* support the writing of the header as detailed in the W3C Technical Report:
|
|
||||||
* </p>
|
|
||||||
* <ul>
|
|
||||||
* <li>Permissions-Policy</li>
|
|
||||||
* </ul>
|
|
||||||
* @return the {@link PermissionsPolicyConfig} for additional configuration
|
|
||||||
* @since 5.5
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicyHeader(Customizer)} or
|
|
||||||
* {@code permissionsPolicy(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
* @see PermissionsPolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public PermissionsPolicyConfig permissionsPolicy() {
|
|
||||||
this.permissionsPolicy.writer = new PermissionsPolicyHeaderWriter();
|
|
||||||
return this.permissionsPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows configuration for
|
* Allows configuration for
|
||||||
* <a href="https://w3c.github.io/webappsec-permissions-policy/"> Permissions
|
* <a href="https://w3c.github.io/webappsec-permissions-policy/"> Permissions
|
||||||
|
@ -643,26 +414,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows configuration for <a href=
|
|
||||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
|
||||||
* Cross-Origin-Opener-Policy</a> header.
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
|
|
||||||
* responsible for writing the header.
|
|
||||||
* </p>
|
|
||||||
* @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration
|
|
||||||
* @since 5.7
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #crossOriginOpenerPolicy(Customizer)}
|
|
||||||
* instead
|
|
||||||
* @see CrossOriginOpenerPolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() {
|
|
||||||
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
|
|
||||||
return this.crossOriginOpenerPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows configuration for <a href=
|
* Allows configuration for <a href=
|
||||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
|
||||||
|
@ -687,26 +438,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows configuration for <a href=
|
|
||||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
|
||||||
* Cross-Origin-Embedder-Policy</a> header.
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
|
|
||||||
* which is responsible for writing the header.
|
|
||||||
* </p>
|
|
||||||
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations
|
|
||||||
* @since 5.7
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #crossOriginEmbedderPolicy(Customizer)}
|
|
||||||
* instead
|
|
||||||
* @see CrossOriginEmbedderPolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() {
|
|
||||||
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
|
|
||||||
return this.crossOriginEmbedderPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows configuration for <a href=
|
* Allows configuration for <a href=
|
||||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
|
||||||
|
@ -731,26 +462,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows configuration for <a href=
|
|
||||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
|
||||||
* Cross-Origin-Resource-Policy</a> header.
|
|
||||||
* <p>
|
|
||||||
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
|
|
||||||
* which is responsible for writing the header:
|
|
||||||
* </p>
|
|
||||||
* @return the {@link HeadersConfigurer} for additional customizations
|
|
||||||
* @since 5.7
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #crossOriginResourcePolicy(Customizer)}
|
|
||||||
* instead
|
|
||||||
* @see CrossOriginResourcePolicyHeaderWriter
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() {
|
|
||||||
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
|
|
||||||
return this.crossOriginResourcePolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows configuration for <a href=
|
* Allows configuration for <a href=
|
||||||
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
|
||||||
|
@ -789,17 +500,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*/
|
*/
|
||||||
public HeadersConfigurer<H> disable() {
|
public HeadersConfigurer<H> disable() {
|
||||||
this.writer = null;
|
this.writer = null;
|
||||||
return and();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows customizing the {@link HeadersConfigurer}
|
|
||||||
* @return the {@link HeadersConfigurer} for additional customization
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,21 +564,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*/
|
*/
|
||||||
public HeadersConfigurer<H> disable() {
|
public HeadersConfigurer<H> disable() {
|
||||||
this.writer = null;
|
this.writer = null;
|
||||||
return and();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of X-XSS-Protection and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or
|
|
||||||
* {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,21 +597,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Cache Control and continuing configuration
|
|
||||||
* of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or
|
|
||||||
* {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures the Cache Control headers are enabled if they are not already.
|
* Ensures the Cache Control headers are enabled if they are not already.
|
||||||
* @return the {@link CacheControlConfig} for additional customization
|
* @return the {@link CacheControlConfig} for additional customization
|
||||||
|
@ -1024,18 +694,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Strict Transport Security and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use
|
|
||||||
* {@link #httpStrictTransportSecurity(Customizer)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that Strict-Transport-Security is enabled if it is not already
|
* Ensures that Strict-Transport-Security is enabled if it is not already
|
||||||
* @return the {@link HstsConfig} for additional customization
|
* @return the {@link HstsConfig} for additional customization
|
||||||
|
@ -1063,7 +721,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*/
|
*/
|
||||||
public HeadersConfigurer<H> deny() {
|
public HeadersConfigurer<H> deny() {
|
||||||
this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY);
|
this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY);
|
||||||
return and();
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1077,7 +735,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*/
|
*/
|
||||||
public HeadersConfigurer<H> sameOrigin() {
|
public HeadersConfigurer<H> sameOrigin() {
|
||||||
this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN);
|
this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN);
|
||||||
return and();
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1086,20 +744,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*/
|
*/
|
||||||
public HeadersConfigurer<H> disable() {
|
public HeadersConfigurer<H> disable() {
|
||||||
this.writer = null;
|
this.writer = null;
|
||||||
return and();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows continuing customizing the headers configuration.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or
|
|
||||||
* {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
return HeadersConfigurer.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1317,18 +961,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Content Security Policy and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class ReferrerPolicyConfig {
|
public final class ReferrerPolicyConfig {
|
||||||
|
@ -1349,18 +981,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or
|
|
||||||
* {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class FeaturePolicyConfig {
|
public final class FeaturePolicyConfig {
|
||||||
|
@ -1399,18 +1019,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Permissions Policy and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class CrossOriginOpenerPolicyConfig {
|
public final class CrossOriginOpenerPolicyConfig {
|
||||||
|
@ -1432,18 +1040,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Cross Origin Opener Policy and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use
|
|
||||||
* {@link #crossOriginOpenerPolicy(Customizer)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class CrossOriginEmbedderPolicyConfig {
|
public final class CrossOriginEmbedderPolicyConfig {
|
||||||
|
@ -1466,18 +1062,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use
|
|
||||||
* {@link #crossOriginEmbedderPolicy(Customizer)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class CrossOriginResourcePolicyConfig {
|
public final class CrossOriginResourcePolicyConfig {
|
||||||
|
@ -1500,18 +1084,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
|
|
||||||
* configuration of headers.
|
|
||||||
* @return the {@link HeadersConfigurer} for additional configuration
|
|
||||||
* @deprecated For removal in 7.0. Use
|
|
||||||
* {@link #crossOriginResourcePolicy(Customizer)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public HeadersConfigurer<H> and() {
|
|
||||||
return HeadersConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
@ -98,7 +99,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#httpBasic()
|
* @see HttpSecurity#httpBasic(Customizer)
|
||||||
*/
|
*/
|
||||||
public HttpBasicConfigurer() {
|
public HttpBasicConfigurer() {
|
||||||
realmName(DEFAULT_REALM);
|
realmName(DEFAULT_REALM);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Set;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
|
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
|
||||||
|
@ -77,7 +78,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#jee()
|
* @see HttpSecurity#jee(Customizer)
|
||||||
*/
|
*/
|
||||||
public JeeConfigurer() {
|
public JeeConfigurer() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||||
|
@ -92,7 +93,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#logout()
|
* @see HttpSecurity#logout(Customizer)
|
||||||
*/
|
*/
|
||||||
public LogoutConfigurer() {
|
public LogoutConfigurer() {
|
||||||
}
|
}
|
||||||
|
@ -150,7 +151,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @param logoutUrl the URL that will invoke logout.
|
* @param logoutUrl the URL that will invoke logout.
|
||||||
* @return the {@link LogoutConfigurer} for further customization
|
* @return the {@link LogoutConfigurer} for further customization
|
||||||
* @see #logoutRequestMatcher(RequestMatcher)
|
* @see #logoutRequestMatcher(RequestMatcher)
|
||||||
* @see HttpSecurity#csrf()
|
* @see HttpSecurity#csrf(Customizer)
|
||||||
*/
|
*/
|
||||||
public LogoutConfigurer<H> logoutUrl(String logoutUrl) {
|
public LogoutConfigurer<H> logoutUrl(String logoutUrl) {
|
||||||
this.logoutRequestMatcher = null;
|
this.logoutRequestMatcher = null;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -145,6 +145,9 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
RequestMatcher notFavIcon = new NegatedRequestMatcher(getFaviconRequestMatcher());
|
RequestMatcher notFavIcon = new NegatedRequestMatcher(getFaviconRequestMatcher());
|
||||||
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
|
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
|
||||||
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
|
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
|
||||||
|
RequestMatcher notWebSocket = new NegatedRequestMatcher(
|
||||||
|
new RequestHeaderRequestMatcher("Upgrade", "websocket"));
|
||||||
|
|
||||||
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
|
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
|
||||||
List<RequestMatcher> matchers = new ArrayList<>();
|
List<RequestMatcher> matchers = new ArrayList<>();
|
||||||
if (isCsrfEnabled) {
|
if (isCsrfEnabled) {
|
||||||
|
@ -156,6 +159,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
matchers.add(notXRequestedWith);
|
matchers.add(notXRequestedWith);
|
||||||
matchers.add(notMatchingMediaType(http, MediaType.MULTIPART_FORM_DATA));
|
matchers.add(notMatchingMediaType(http, MediaType.MULTIPART_FORM_DATA));
|
||||||
matchers.add(notMatchingMediaType(http, MediaType.TEXT_EVENT_STREAM));
|
matchers.add(notMatchingMediaType(http, MediaType.TEXT_EVENT_STREAM));
|
||||||
|
matchers.add(notWebSocket);
|
||||||
return new AndRequestMatcher(matchers);
|
return new AndRequestMatcher(matchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.web.configurers;
|
package org.springframework.security.config.annotation.web.configurers;
|
||||||
|
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
@ -70,7 +71,7 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#securityContext()
|
* @see HttpSecurity#securityContext(Customizer)
|
||||||
*/
|
*/
|
||||||
public SecurityContextConfigurer() {
|
public SecurityContextConfigurer() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||||
|
@ -66,7 +67,7 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#servletApi()
|
* @see HttpSecurity#servletApi(Customizer)
|
||||||
*/
|
*/
|
||||||
public ServletApiConfigurer() {
|
public ServletApiConfigurer() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#sessionManagement()
|
* @see HttpSecurity#sessionManagement(Customizer)
|
||||||
*/
|
*/
|
||||||
public SessionManagementConfigurer() {
|
public SessionManagementConfigurer() {
|
||||||
}
|
}
|
||||||
|
@ -775,17 +775,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to chain back to the {@link SessionManagementConfigurer}
|
|
||||||
* @return the {@link SessionManagementConfigurer} for further customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #sessionConcurrency(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public SessionManagementConfigurer<H> and() {
|
|
||||||
return SessionManagementConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
}
|
}
|
||||||
|
|
||||||
public H and() {
|
public H and() {
|
||||||
return UrlAuthorizationConfigurer.this.and();
|
return UrlAuthorizationConfigurer.this.getBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import org.springframework.security.web.webauthn.registration.DefaultWebAuthnReg
|
||||||
import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsFilter;
|
import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsFilter;
|
||||||
import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsRepository;
|
import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsRepository;
|
||||||
import org.springframework.security.web.webauthn.registration.WebAuthnRegistrationFilter;
|
import org.springframework.security.web.webauthn.registration.WebAuthnRegistrationFilter;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures WebAuthn for Spring Security applications
|
* Configures WebAuthn for Spring Security applications
|
||||||
|
@ -75,6 +76,7 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @return the {@link WebAuthnConfigurer} for further customization
|
* @return the {@link WebAuthnConfigurer} for further customization
|
||||||
*/
|
*/
|
||||||
public WebAuthnConfigurer<H> rpId(String rpId) {
|
public WebAuthnConfigurer<H> rpId(String rpId) {
|
||||||
|
Assert.hasText(rpId, "rpId be null or empty");
|
||||||
this.rpId = rpId;
|
this.rpId = rpId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +87,7 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @return the {@link WebAuthnConfigurer} for further customization
|
* @return the {@link WebAuthnConfigurer} for further customization
|
||||||
*/
|
*/
|
||||||
public WebAuthnConfigurer<H> rpName(String rpName) {
|
public WebAuthnConfigurer<H> rpName(String rpName) {
|
||||||
|
Assert.hasText(rpName, "rpName can't be null or empty");
|
||||||
this.rpName = rpName;
|
this.rpName = rpName;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -106,6 +109,7 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @see #allowedOrigins(String...)
|
* @see #allowedOrigins(String...)
|
||||||
*/
|
*/
|
||||||
public WebAuthnConfigurer<H> allowedOrigins(Set<String> allowedOrigins) {
|
public WebAuthnConfigurer<H> allowedOrigins(Set<String> allowedOrigins) {
|
||||||
|
Assert.notNull(allowedOrigins, "allowedOrigins can't be null");
|
||||||
this.allowedOrigins = allowedOrigins;
|
this.allowedOrigins = allowedOrigins;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +133,7 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @return the {@link WebAuthnConfigurer} for further customization
|
* @return the {@link WebAuthnConfigurer} for further customization
|
||||||
*/
|
*/
|
||||||
public WebAuthnConfigurer<H> messageConverter(HttpMessageConverter<Object> converter) {
|
public WebAuthnConfigurer<H> messageConverter(HttpMessageConverter<Object> converter) {
|
||||||
|
Assert.notNull(converter, "converter can't be null");
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -140,15 +145,15 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
*/
|
*/
|
||||||
public WebAuthnConfigurer<H> creationOptionsRepository(
|
public WebAuthnConfigurer<H> creationOptionsRepository(
|
||||||
PublicKeyCredentialCreationOptionsRepository creationOptionsRepository) {
|
PublicKeyCredentialCreationOptionsRepository creationOptionsRepository) {
|
||||||
|
Assert.notNull(creationOptionsRepository, "creationOptionsRepository can't be null");
|
||||||
this.creationOptionsRepository = creationOptionsRepository;
|
this.creationOptionsRepository = creationOptionsRepository;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(H http) throws Exception {
|
public void configure(H http) throws Exception {
|
||||||
UserDetailsService userDetailsService = getSharedOrBean(http, UserDetailsService.class).orElseGet(() -> {
|
UserDetailsService userDetailsService = getSharedOrBean(http, UserDetailsService.class)
|
||||||
throw new IllegalStateException("Missing UserDetailsService Bean");
|
.orElseThrow(() -> new IllegalStateException("Missing UserDetailsService Bean"));
|
||||||
});
|
|
||||||
PublicKeyCredentialUserEntityRepository userEntities = getSharedOrBean(http,
|
PublicKeyCredentialUserEntityRepository userEntities = getSharedOrBean(http,
|
||||||
PublicKeyCredentialUserEntityRepository.class)
|
PublicKeyCredentialUserEntityRepository.class)
|
||||||
.orElse(userEntityRepository());
|
.orElse(userEntityRepository());
|
||||||
|
@ -238,12 +243,9 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
PublicKeyCredentialUserEntityRepository userEntities, UserCredentialRepository userCredentials) {
|
PublicKeyCredentialUserEntityRepository userEntities, UserCredentialRepository userCredentials) {
|
||||||
Optional<WebAuthnRelyingPartyOperations> webauthnOperationsBean = getBeanOrNull(
|
Optional<WebAuthnRelyingPartyOperations> webauthnOperationsBean = getBeanOrNull(
|
||||||
WebAuthnRelyingPartyOperations.class);
|
WebAuthnRelyingPartyOperations.class);
|
||||||
if (webauthnOperationsBean.isPresent()) {
|
return webauthnOperationsBean.orElseGet(() -> new Webauthn4JRelyingPartyOperations(userEntities,
|
||||||
return webauthnOperationsBean.get();
|
userCredentials, PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(),
|
||||||
}
|
this.allowedOrigins));
|
||||||
Webauthn4JRelyingPartyOperations result = new Webauthn4JRelyingPartyOperations(userEntities, userCredentials,
|
|
||||||
PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(), this.allowedOrigins);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -21,6 +21,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
@ -90,7 +91,7 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
*
|
*
|
||||||
* @see HttpSecurity#x509()
|
* @see HttpSecurity#x509(Customizer)
|
||||||
*/
|
*/
|
||||||
public X509Configurer() {
|
public X509Configurer() {
|
||||||
}
|
}
|
||||||
|
@ -161,7 +162,10 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @param subjectPrincipalRegex the regex to extract the user principal from the
|
* @param subjectPrincipalRegex the regex to extract the user principal from the
|
||||||
* certificate (i.e. "CN=(.*?)(?:,|$)").
|
* certificate (i.e. "CN=(.*?)(?:,|$)").
|
||||||
* @return the {@link X509Configurer} for further customizations
|
* @return the {@link X509Configurer} for further customizations
|
||||||
|
* @deprecated Please use {{@link #x509PrincipalExtractor(X509PrincipalExtractor)}
|
||||||
|
* instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public X509Configurer<H> subjectPrincipalRegex(String subjectPrincipalRegex) {
|
public X509Configurer<H> subjectPrincipalRegex(String subjectPrincipalRegex) {
|
||||||
SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor();
|
SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor();
|
||||||
principalExtractor.setSubjectDnRegex(subjectPrincipalRegex);
|
principalExtractor.setSubjectDnRegex(subjectPrincipalRegex);
|
||||||
|
|
|
@ -141,18 +141,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link AuthorizationCodeGrantConfigurer} for configuring the OAuth 2.0
|
|
||||||
* Authorization Code Grant.
|
|
||||||
* @return the {@link AuthorizationCodeGrantConfigurer}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public AuthorizationCodeGrantConfigurer authorizationCodeGrant() {
|
|
||||||
return this.authorizationCodeGrantConfigurer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the OAuth 2.0 Authorization Code Grant.
|
* Configures the OAuth 2.0 Authorization Code Grant.
|
||||||
* @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more
|
* @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more
|
||||||
|
@ -242,17 +230,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link OAuth2ClientConfigurer} for further configuration.
|
|
||||||
* @return the {@link OAuth2ClientConfigurer}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OAuth2ClientConfigurer<B> and() {
|
|
||||||
return OAuth2ClientConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(B builder) {
|
private void init(B builder) {
|
||||||
OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider(
|
OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider(
|
||||||
getAccessTokenResponseClient());
|
getAccessTokenResponseClient());
|
||||||
|
|
|
@ -155,7 +155,7 @@ import org.springframework.util.ReflectionUtils;
|
||||||
* @author Kazuki Shimizu
|
* @author Kazuki Shimizu
|
||||||
* @author Ngoc Nhan
|
* @author Ngoc Nhan
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see HttpSecurity#oauth2Login()
|
* @see HttpSecurity#oauth2Login(Customizer)
|
||||||
* @see OAuth2AuthorizationRequestRedirectFilter
|
* @see OAuth2AuthorizationRequestRedirectFilter
|
||||||
* @see OAuth2LoginAuthenticationFilter
|
* @see OAuth2LoginAuthenticationFilter
|
||||||
* @see ClientRegistrationRepository
|
* @see ClientRegistrationRepository
|
||||||
|
@ -246,18 +246,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link AuthorizationEndpointConfig} for configuring the Authorization
|
|
||||||
* Server's Authorization Endpoint.
|
|
||||||
* @return the {@link AuthorizationEndpointConfig}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public AuthorizationEndpointConfig authorizationEndpoint() {
|
|
||||||
return this.authorizationEndpointConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the Authorization Server's Authorization Endpoint.
|
* Configures the Authorization Server's Authorization Endpoint.
|
||||||
* @param authorizationEndpointCustomizer the {@link Customizer} to provide more
|
* @param authorizationEndpointCustomizer the {@link Customizer} to provide more
|
||||||
|
@ -270,21 +258,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link TokenEndpointConfig} for configuring the Authorization Server's
|
|
||||||
* Token Endpoint.
|
|
||||||
* @return the {@link TokenEndpointConfig}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or
|
|
||||||
* {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public TokenEndpointConfig tokenEndpoint() {
|
|
||||||
return this.tokenEndpointConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the Authorization Server's Token Endpoint.
|
* Configures the Authorization Server's Token Endpoint.
|
||||||
* @param tokenEndpointCustomizer the {@link Customizer} to provide more options for
|
* @param tokenEndpointCustomizer the {@link Customizer} to provide more options for
|
||||||
|
@ -297,18 +270,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link RedirectionEndpointConfig} for configuring the Client's
|
|
||||||
* Redirection Endpoint.
|
|
||||||
* @return the {@link RedirectionEndpointConfig}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public RedirectionEndpointConfig redirectionEndpoint() {
|
|
||||||
return this.redirectionEndpointConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the Client's Redirection Endpoint.
|
* Configures the Client's Redirection Endpoint.
|
||||||
* @param redirectionEndpointCustomizer the {@link Customizer} to provide more options
|
* @param redirectionEndpointCustomizer the {@link Customizer} to provide more options
|
||||||
|
@ -321,21 +282,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link UserInfoEndpointConfig} for configuring the Authorization
|
|
||||||
* Server's UserInfo Endpoint.
|
|
||||||
* @return the {@link UserInfoEndpointConfig}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)} or
|
|
||||||
* {@code userInfoEndpoint(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public UserInfoEndpointConfig userInfoEndpoint() {
|
|
||||||
return this.userInfoEndpointConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the Authorization Server's UserInfo Endpoint.
|
* Configures the Authorization Server's UserInfo Endpoint.
|
||||||
* @param userInfoEndpointCustomizer the {@link Customizer} to provide more options
|
* @param userInfoEndpointCustomizer the {@link Customizer} to provide more options
|
||||||
|
@ -404,11 +350,9 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper);
|
oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper);
|
||||||
oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper);
|
oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper);
|
||||||
}
|
}
|
||||||
oidcAuthorizationCodeAuthenticationProvider = this.postProcess(oidcAuthorizationCodeAuthenticationProvider);
|
http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider));
|
||||||
http.authenticationProvider(oidcAuthorizationCodeAuthenticationProvider);
|
|
||||||
|
|
||||||
oidcAuthorizedClientRefreshedEventListener = this.postProcess(oidcAuthorizedClientRefreshedEventListener);
|
registerDelegateApplicationListener(this.postProcess(oidcAuthorizedClientRefreshedEventListener));
|
||||||
registerDelegateApplicationListener(oidcAuthorizedClientRefreshedEventListener);
|
|
||||||
configureOidcUserRefreshedEventListener(http);
|
configureOidcUserRefreshedEventListener(http);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -724,17 +668,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
|
||||||
* @return the {@link OAuth2LoginConfigurer}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OAuth2LoginConfigurer<B> and() {
|
|
||||||
return OAuth2LoginConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -761,20 +694,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
|
||||||
* @return the {@link OAuth2LoginConfigurer}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or
|
|
||||||
* {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OAuth2LoginConfigurer<B> and() {
|
|
||||||
return OAuth2LoginConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -799,17 +718,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
|
||||||
* @return the {@link OAuth2LoginConfigurer}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OAuth2LoginConfigurer<B> and() {
|
|
||||||
return OAuth2LoginConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -864,17 +772,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link OAuth2LoginConfigurer} for further configuration.
|
|
||||||
* @return the {@link OAuth2LoginConfigurer}
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OAuth2LoginConfigurer<B> and() {
|
|
||||||
return OAuth2LoginConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class OidcAuthenticationRequestChecker implements AuthenticationProvider {
|
private static class OidcAuthenticationRequestChecker implements AuthenticationProvider {
|
||||||
|
|
|
@ -18,11 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.cl
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import com.nimbusds.jose.JOSEObjectType;
|
|
||||||
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
|
|
||||||
import com.nimbusds.jose.proc.JOSEObjectTypeVerifier;
|
|
||||||
import com.nimbusds.jose.proc.SecurityContext;
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
@ -38,6 +33,7 @@ import org.springframework.security.oauth2.jwt.BadJwtException;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
|
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtTypeValidator;
|
||||||
import org.springframework.security.oauth2.jwt.JwtValidators;
|
import org.springframework.security.oauth2.jwt.JwtValidators;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -67,8 +63,10 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio
|
||||||
* Construct an {@link OidcBackChannelLogoutAuthenticationProvider}
|
* Construct an {@link OidcBackChannelLogoutAuthenticationProvider}
|
||||||
*/
|
*/
|
||||||
OidcBackChannelLogoutAuthenticationProvider() {
|
OidcBackChannelLogoutAuthenticationProvider() {
|
||||||
|
JwtTypeValidator type = new JwtTypeValidator("JWT", "logout+jwt");
|
||||||
|
type.setAllowEmpty(true);
|
||||||
Function<ClientRegistration, OAuth2TokenValidator<Jwt>> jwtValidator = (clientRegistration) -> JwtValidators
|
Function<ClientRegistration, OAuth2TokenValidator<Jwt>> jwtValidator = (clientRegistration) -> JwtValidators
|
||||||
.createDefaultWithValidators(new OidcBackChannelLogoutTokenValidator(clientRegistration));
|
.createDefaultWithValidators(type, new OidcBackChannelLogoutTokenValidator(clientRegistration));
|
||||||
this.logoutTokenDecoderFactory = (clientRegistration) -> {
|
this.logoutTokenDecoderFactory = (clientRegistration) -> {
|
||||||
String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri();
|
String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri();
|
||||||
if (!StringUtils.hasText(jwkSetUri)) {
|
if (!StringUtils.hasText(jwkSetUri)) {
|
||||||
|
@ -79,11 +77,7 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio
|
||||||
null);
|
null);
|
||||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||||
}
|
}
|
||||||
JOSEObjectTypeVerifier<SecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(null,
|
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
|
||||||
JOSEObjectType.JWT, new JOSEObjectType("logout+jwt"));
|
|
||||||
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
|
|
||||||
.jwtProcessorCustomizer((processor) -> processor.setJWSTypeVerifier(typeVerifier))
|
|
||||||
.build();
|
|
||||||
decoder.setJwtValidator(jwtValidator.apply(clientRegistration));
|
decoder.setJwtValidator(jwtValidator.apply(clientRegistration));
|
||||||
decoder.setClaimSetConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverter());
|
decoder.setClaimSetConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverter());
|
||||||
return decoder;
|
return decoder;
|
||||||
|
|
|
@ -127,7 +127,7 @@ public final class OidcBackChannelLogoutHandler implements LogoutHandler {
|
||||||
String computeLogoutEndpoint(HttpServletRequest request, OidcBackChannelLogoutAuthentication token) {
|
String computeLogoutEndpoint(HttpServletRequest request, OidcBackChannelLogoutAuthentication token) {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
UriComponents uriComponents = UriComponentsBuilder
|
UriComponents uriComponents = UriComponentsBuilder
|
||||||
.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
|
.fromUriString(UrlUtils.buildFullRequestUrl(request))
|
||||||
.replacePath(request.getContextPath())
|
.replacePath(request.getContextPath())
|
||||||
.replaceQuery(null)
|
.replaceQuery(null)
|
||||||
.fragment(null)
|
.fragment(null)
|
||||||
|
|
|
@ -111,11 +111,6 @@ public final class OidcLogoutConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated(forRemoval = true, since = "6.2")
|
|
||||||
public B and() {
|
|
||||||
return getBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(B builder) throws Exception {
|
public void configure(B builder) throws Exception {
|
||||||
if (this.backChannel != null) {
|
if (this.backChannel != null) {
|
||||||
|
|
|
@ -17,39 +17,54 @@
|
||||||
package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource;
|
package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationProvider;
|
import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationProvider;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken;
|
import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||||
import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler;
|
import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler;
|
||||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||||
import org.springframework.security.web.authentication.AuthenticationFilter;
|
import org.springframework.security.web.authentication.AuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
|
||||||
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* An {@link AbstractHttpConfigurer} for OAuth 2.0 Demonstrating Proof of Possession
|
||||||
|
* (DPoP) support.
|
||||||
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 6.5
|
* @since 6.5
|
||||||
* @see DPoPAuthenticationProvider
|
* @see DPoPAuthenticationProvider
|
||||||
|
* @see <a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc9449">RFC 9449
|
||||||
|
* OAuth 2.0 Demonstrating Proof of Possession (DPoP)</a>
|
||||||
*/
|
*/
|
||||||
final class DPoPAuthenticationConfigurer<B extends HttpSecurityBuilder<B>>
|
final class DPoPAuthenticationConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
extends AbstractHttpConfigurer<DPoPAuthenticationConfigurer<B>, B> {
|
extends AbstractHttpConfigurer<DPoPAuthenticationConfigurer<B>, B> {
|
||||||
|
@ -65,7 +80,7 @@ final class DPoPAuthenticationConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
@Override
|
@Override
|
||||||
public void configure(B http) {
|
public void configure(B http) {
|
||||||
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
|
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
|
||||||
http.authenticationProvider(new DPoPAuthenticationProvider(authenticationManager));
|
http.authenticationProvider(new DPoPAuthenticationProvider(getTokenAuthenticationManager(http)));
|
||||||
AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager,
|
AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager,
|
||||||
getAuthenticationConverter());
|
getAuthenticationConverter());
|
||||||
authenticationFilter.setRequestMatcher(getRequestMatcher());
|
authenticationFilter.setRequestMatcher(getRequestMatcher());
|
||||||
|
@ -76,6 +91,23 @@ final class DPoPAuthenticationConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
http.addFilter(authenticationFilter);
|
http.addFilter(authenticationFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AuthenticationManager getTokenAuthenticationManager(B http) {
|
||||||
|
OAuth2ResourceServerConfigurer<B> resourceServerConfigurer = http
|
||||||
|
.getConfigurer(OAuth2ResourceServerConfigurer.class);
|
||||||
|
final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver = resourceServerConfigurer
|
||||||
|
.getAuthenticationManagerResolver();
|
||||||
|
if (authenticationManagerResolver == null) {
|
||||||
|
return resourceServerConfigurer.getAuthenticationManager(http);
|
||||||
|
}
|
||||||
|
return (authentication) -> {
|
||||||
|
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||||
|
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||||
|
AuthenticationManager authenticationManager = authenticationManagerResolver
|
||||||
|
.resolve(servletRequestAttributes.getRequest());
|
||||||
|
return authenticationManager.authenticate(authentication);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private RequestMatcher getRequestMatcher() {
|
private RequestMatcher getRequestMatcher() {
|
||||||
if (this.requestMatcher == null) {
|
if (this.requestMatcher == null) {
|
||||||
this.requestMatcher = new DPoPRequestMatcher();
|
this.requestMatcher = new DPoPRequestMatcher();
|
||||||
|
@ -102,7 +134,7 @@ final class DPoPAuthenticationConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
private AuthenticationFailureHandler getAuthenticationFailureHandler() {
|
private AuthenticationFailureHandler getAuthenticationFailureHandler() {
|
||||||
if (this.authenticationFailureHandler == null) {
|
if (this.authenticationFailureHandler == null) {
|
||||||
this.authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(
|
this.authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(
|
||||||
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
|
new DPoPAuthenticationEntryPoint());
|
||||||
}
|
}
|
||||||
return this.authenticationFailureHandler;
|
return this.authenticationFailureHandler;
|
||||||
}
|
}
|
||||||
|
@ -161,4 +193,47 @@ final class DPoPAuthenticationConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class DPoPAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
AuthenticationException authenticationException) {
|
||||||
|
Map<String, String> parameters = new LinkedHashMap<>();
|
||||||
|
if (authenticationException instanceof OAuth2AuthenticationException oauth2AuthenticationException) {
|
||||||
|
OAuth2Error error = oauth2AuthenticationException.getError();
|
||||||
|
parameters.put(OAuth2ParameterNames.ERROR, error.getErrorCode());
|
||||||
|
if (StringUtils.hasText(error.getDescription())) {
|
||||||
|
parameters.put(OAuth2ParameterNames.ERROR_DESCRIPTION, error.getDescription());
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(error.getUri())) {
|
||||||
|
parameters.put(OAuth2ParameterNames.ERROR_URI, error.getUri());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parameters.put("algs",
|
||||||
|
JwsAlgorithms.RS256 + " " + JwsAlgorithms.RS384 + " " + JwsAlgorithms.RS512 + " "
|
||||||
|
+ JwsAlgorithms.PS256 + " " + JwsAlgorithms.PS384 + " " + JwsAlgorithms.PS512 + " "
|
||||||
|
+ JwsAlgorithms.ES256 + " " + JwsAlgorithms.ES384 + " " + JwsAlgorithms.ES512);
|
||||||
|
String wwwAuthenticate = toWWWAuthenticateHeader(parameters);
|
||||||
|
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, wwwAuthenticate);
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toWWWAuthenticateHeader(Map<String, String> parameters) {
|
||||||
|
StringBuilder wwwAuthenticate = new StringBuilder();
|
||||||
|
wwwAuthenticate.append(OAuth2AccessToken.TokenType.DPOP.getValue());
|
||||||
|
if (!parameters.isEmpty()) {
|
||||||
|
wwwAuthenticate.append(" ");
|
||||||
|
int i = 0;
|
||||||
|
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||||
|
wwwAuthenticate.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
|
||||||
|
if (i++ != parameters.size() - 1) {
|
||||||
|
wwwAuthenticate.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wwwAuthenticate.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||||
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
@ -49,13 +50,14 @@ import org.springframework.security.oauth2.server.resource.introspection.OpaqueT
|
||||||
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
|
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
|
||||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
|
||||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||||
|
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter;
|
||||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||||
import org.springframework.security.web.csrf.CsrfException;
|
import org.springframework.security.web.csrf.CsrfException;
|
||||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||||
|
@ -156,7 +158,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
|
|
||||||
private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
||||||
|
|
||||||
private BearerTokenResolver bearerTokenResolver;
|
private AuthenticationConverter authenticationConverter;
|
||||||
|
|
||||||
private JwtConfigurer jwtConfigurer;
|
private JwtConfigurer jwtConfigurer;
|
||||||
|
|
||||||
|
@ -196,22 +198,20 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
|
|
||||||
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
||||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
||||||
this.bearerTokenResolver = bearerTokenResolver;
|
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
* Sets the {@link AuthenticationConverter} to use.
|
||||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
* @param authenticationConverter the authentication converter
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
* @return the {@link OAuth2ResourceServerConfigurer} for further configuration
|
||||||
* for more details.
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||||
public JwtConfigurer jwt() {
|
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||||
if (this.jwtConfigurer == null) {
|
this.authenticationConverter = authenticationConverter;
|
||||||
this.jwtConfigurer = new JwtConfigurer(this.context);
|
return this;
|
||||||
}
|
|
||||||
return this.jwtConfigurer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,21 +228,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)} or
|
|
||||||
* {@code opaqueToken(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OpaqueTokenConfigurer opaqueToken() {
|
|
||||||
if (this.opaqueTokenConfigurer == null) {
|
|
||||||
this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
|
|
||||||
}
|
|
||||||
return this.opaqueTokenConfigurer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables opaque bearer token support.
|
* Enables opaque bearer token support.
|
||||||
* @param opaqueTokenCustomizer the {@link Customizer} to provide more options for the
|
* @param opaqueTokenCustomizer the {@link Customizer} to provide more options for the
|
||||||
|
@ -271,16 +256,15 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(H http) {
|
public void configure(H http) {
|
||||||
BearerTokenResolver bearerTokenResolver = getBearerTokenResolver();
|
|
||||||
this.requestMatcher.setBearerTokenResolver(bearerTokenResolver);
|
|
||||||
AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
|
AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
|
||||||
if (resolver == null) {
|
if (resolver == null) {
|
||||||
AuthenticationManager authenticationManager = getAuthenticationManager(http);
|
AuthenticationManager authenticationManager = getAuthenticationManager(http);
|
||||||
resolver = (request) -> authenticationManager;
|
resolver = (request) -> authenticationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
AuthenticationConverter converter = getAuthenticationConverter();
|
||||||
filter.setBearerTokenResolver(bearerTokenResolver);
|
this.requestMatcher.setAuthenticationConverter(converter);
|
||||||
|
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver, converter);
|
||||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||||
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||||
filter = postProcess(filter);
|
filter = postProcess(filter);
|
||||||
|
@ -363,16 +347,33 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
return http.getSharedObject(AuthenticationManager.class);
|
return http.getSharedObject(AuthenticationManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
BearerTokenResolver getBearerTokenResolver() {
|
AuthenticationManagerResolver<HttpServletRequest> getAuthenticationManagerResolver() {
|
||||||
if (this.bearerTokenResolver == null) {
|
return this.authenticationManagerResolver;
|
||||||
if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
}
|
||||||
this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
|
||||||
}
|
AuthenticationConverter getAuthenticationConverter() {
|
||||||
else {
|
if (this.authenticationConverter != null) {
|
||||||
this.bearerTokenResolver = new DefaultBearerTokenResolver();
|
return this.authenticationConverter;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this.bearerTokenResolver;
|
if (this.context.getBeanNamesForType(AuthenticationConverter.class).length > 0) {
|
||||||
|
this.authenticationConverter = this.context.getBean(AuthenticationConverter.class);
|
||||||
|
}
|
||||||
|
else if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
||||||
|
BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
||||||
|
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||||
|
}
|
||||||
|
return this.authenticationConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
BearerTokenResolver getBearerTokenResolver() {
|
||||||
|
AuthenticationConverter authenticationConverter = getAuthenticationConverter();
|
||||||
|
if (authenticationConverter instanceof OAuth2ResourceServerConfigurer.BearerTokenResolverHoldingAuthenticationConverter bearer) {
|
||||||
|
return bearer.bearerTokenResolver;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JwtConfigurer {
|
public class JwtConfigurer {
|
||||||
|
@ -411,17 +412,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
|
||||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public OAuth2ResourceServerConfigurer<H> and() {
|
|
||||||
return OAuth2ResourceServerConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Converter<Jwt, ? extends AbstractAuthenticationToken> getJwtAuthenticationConverter() {
|
Converter<Jwt, ? extends AbstractAuthenticationToken> getJwtAuthenticationConverter() {
|
||||||
if (this.jwtAuthenticationConverter == null) {
|
if (this.jwtAuthenticationConverter == null) {
|
||||||
if (this.context.getBeanNamesForType(JwtAuthenticationConverter.class).length > 0) {
|
if (this.context.getBeanNamesForType(JwtAuthenticationConverter.class).length > 0) {
|
||||||
|
@ -560,21 +550,41 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||||
|
|
||||||
private static final class BearerTokenRequestMatcher implements RequestMatcher {
|
private static final class BearerTokenRequestMatcher implements RequestMatcher {
|
||||||
|
|
||||||
private BearerTokenResolver bearerTokenResolver;
|
private AuthenticationConverter authenticationConverter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(HttpServletRequest request) {
|
public boolean matches(HttpServletRequest request) {
|
||||||
try {
|
try {
|
||||||
return this.bearerTokenResolver.resolve(request) != null;
|
return this.authenticationConverter.convert(request) != null;
|
||||||
}
|
}
|
||||||
catch (OAuth2AuthenticationException ex) {
|
catch (OAuth2AuthenticationException ex) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBearerTokenResolver(BearerTokenResolver tokenResolver) {
|
void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||||
Assert.notNull(tokenResolver, "resolver cannot be null");
|
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||||
this.bearerTokenResolver = tokenResolver;
|
this.authenticationConverter = authenticationConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class BearerTokenResolverHoldingAuthenticationConverter implements AuthenticationConverter {
|
||||||
|
|
||||||
|
private final BearerTokenResolver bearerTokenResolver;
|
||||||
|
|
||||||
|
private final AuthenticationConverter authenticationConverter;
|
||||||
|
|
||||||
|
BearerTokenResolverHoldingAuthenticationConverter(BearerTokenResolver bearerTokenResolver) {
|
||||||
|
this.bearerTokenResolver = bearerTokenResolver;
|
||||||
|
BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||||
|
authenticationConverter.setBearerTokenResolver(bearerTokenResolver);
|
||||||
|
this.authenticationConverter = authenticationConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication convert(HttpServletRequest request) {
|
||||||
|
return this.authenticationConverter.convert(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.opensaml.core.Version;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
import org.springframework.security.config.annotation.web.RequestMatcherFactory;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
@ -111,7 +112,7 @@ import org.springframework.util.StringUtils;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
* @see HttpSecurity#saml2Login()
|
* @see HttpSecurity#saml2Login(Customizer)
|
||||||
* @see Saml2WebSsoAuthenticationFilter
|
* @see Saml2WebSsoAuthenticationFilter
|
||||||
* @see Saml2WebSsoAuthenticationRequestFilter
|
* @see Saml2WebSsoAuthenticationRequestFilter
|
||||||
* @see RelyingPartyRegistrationRepository
|
* @see RelyingPartyRegistrationRepository
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.springframework.security.config.annotation.web.configurers.LogoutConf
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutRequestValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutRequestValidator;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutResponseValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutResponseValidator;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml5LogoutRequestValidator;
|
import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml5LogoutRequestValidator;
|
||||||
|
@ -133,7 +135,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
* @see HttpSecurity#logout()
|
* @see HttpSecurity#logout(Customizer)
|
||||||
*/
|
*/
|
||||||
public Saml2LogoutConfigurer(ApplicationContext context) {
|
public Saml2LogoutConfigurer(ApplicationContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -156,7 +158,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
* @param logoutUrl the URL that will invoke logout
|
* @param logoutUrl the URL that will invoke logout
|
||||||
* @return the {@link LogoutConfigurer} for further customizations
|
* @return the {@link LogoutConfigurer} for further customizations
|
||||||
* @see LogoutConfigurer#logoutUrl(String)
|
* @see LogoutConfigurer#logoutUrl(String)
|
||||||
* @see HttpSecurity#csrf()
|
* @see HttpSecurity#csrf(Customizer)
|
||||||
*/
|
*/
|
||||||
public Saml2LogoutConfigurer<H> logoutUrl(String logoutUrl) {
|
public Saml2LogoutConfigurer<H> logoutUrl(String logoutUrl) {
|
||||||
this.logoutUrl = logoutUrl;
|
this.logoutUrl = logoutUrl;
|
||||||
|
@ -175,20 +177,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get configurer for SAML 2.0 Logout Request components
|
|
||||||
* @return the {@link LogoutRequestConfigurer} for further customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #logoutRequest(Customizer)} or
|
|
||||||
* {@code logoutRequest(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public LogoutRequestConfigurer logoutRequest() {
|
|
||||||
return this.logoutRequestConfigurer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures SAML 2.0 Logout Request components
|
* Configures SAML 2.0 Logout Request components
|
||||||
* @param logoutRequestConfigurerCustomizer the {@link Customizer} to provide more
|
* @param logoutRequestConfigurerCustomizer the {@link Customizer} to provide more
|
||||||
|
@ -201,20 +189,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get configurer for SAML 2.0 Logout Response components
|
|
||||||
* @return the {@link LogoutResponseConfigurer} for further customizations
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #logoutResponse(Customizer)} or
|
|
||||||
* {@code logoutResponse(Customizer.withDefaults())} to stick with defaults. See the
|
|
||||||
* <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public LogoutResponseConfigurer logoutResponse() {
|
|
||||||
return this.logoutResponseConfigurer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures SAML 2.0 Logout Response components
|
* Configures SAML 2.0 Logout Response components
|
||||||
* @param logoutResponseConfigurerCustomizer the {@link Customizer} to provide more
|
* @param logoutResponseConfigurerCustomizer the {@link Customizer} to provide more
|
||||||
|
@ -404,18 +378,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #logoutRequest(Customizer)} or
|
|
||||||
* {@code logoutRequest(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public Saml2LogoutConfigurer<H> and() {
|
|
||||||
return Saml2LogoutConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Saml2LogoutRequestValidator logoutRequestValidator() {
|
private Saml2LogoutRequestValidator logoutRequestValidator() {
|
||||||
if (this.logoutRequestValidator != null) {
|
if (this.logoutRequestValidator != null) {
|
||||||
return this.logoutRequestValidator;
|
return this.logoutRequestValidator;
|
||||||
|
@ -486,18 +448,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated For removal in 7.0. Use {@link #logoutResponse(Customizer)} or
|
|
||||||
* {@code logoutResponse(Customizer.withDefaults())} to stick with defaults. See
|
|
||||||
* the <a href=
|
|
||||||
* "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
|
|
||||||
* for more details.
|
|
||||||
*/
|
|
||||||
@Deprecated(since = "6.1", forRemoval = true)
|
|
||||||
public Saml2LogoutConfigurer<H> and() {
|
|
||||||
return Saml2LogoutConfigurer.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Saml2LogoutResponseValidator logoutResponseValidator() {
|
private Saml2LogoutResponseValidator logoutResponseValidator() {
|
||||||
if (this.logoutResponseValidator != null) {
|
if (this.logoutResponseValidator != null) {
|
||||||
return this.logoutResponseValidator;
|
return this.logoutResponseValidator;
|
||||||
|
@ -534,7 +484,13 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
if (authentication == null) {
|
if (authentication == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal;
|
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return authentication instanceof Saml2Authentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ import org.springframework.security.web.reactive.result.method.annotation.Curren
|
||||||
import org.springframework.web.reactive.config.WebFluxConfigurer;
|
import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||||
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
||||||
|
|
||||||
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Dan Zheng
|
* @author Dan Zheng
|
||||||
|
@ -156,8 +158,8 @@ class ServerHttpSecurityConfiguration {
|
||||||
ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity();
|
ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity();
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
return http.authenticationManager(authenticationManager())
|
return http.authenticationManager(authenticationManager())
|
||||||
.headers().and()
|
.headers(withDefaults())
|
||||||
.logout().and();
|
.logout(withDefaults());
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.web.reactive.result.view.AbstractView;
|
import org.springframework.web.reactive.result.view.AbstractView;
|
||||||
|
|
||||||
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
@ -121,13 +123,13 @@ class WebFluxSecurityConfiguration {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
private SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
http.authorizeExchange().anyExchange().authenticated();
|
http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated());
|
||||||
if (isOAuth2Present && OAuth2ClasspathGuard.shouldConfigure(this.context)) {
|
if (isOAuth2Present && OAuth2ClasspathGuard.shouldConfigure(this.context)) {
|
||||||
OAuth2ClasspathGuard.configure(this.context, http);
|
OAuth2ClasspathGuard.configure(this.context, http);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
http.httpBasic();
|
http.httpBasic(withDefaults());
|
||||||
http.formLogin();
|
http.formLogin(withDefaults());
|
||||||
}
|
}
|
||||||
SecurityWebFilterChain result = http.build();
|
SecurityWebFilterChain result = http.build();
|
||||||
return result;
|
return result;
|
||||||
|
@ -136,8 +138,8 @@ class WebFluxSecurityConfiguration {
|
||||||
private static class OAuth2ClasspathGuard {
|
private static class OAuth2ClasspathGuard {
|
||||||
|
|
||||||
static void configure(ApplicationContext context, ServerHttpSecurity http) {
|
static void configure(ApplicationContext context, ServerHttpSecurity http) {
|
||||||
http.oauth2Login();
|
http.oauth2Login(withDefaults());
|
||||||
http.oauth2Client();
|
http.oauth2Client(withDefaults());
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean shouldConfigure(ApplicationContext context) {
|
static boolean shouldConfigure(ApplicationContext context) {
|
||||||
|
|
|
@ -1,286 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2022 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.web.socket;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.messaging.Message;
|
|
||||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
|
||||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
|
||||||
import org.springframework.messaging.simp.config.ChannelRegistration;
|
|
||||||
import org.springframework.security.access.AccessDecisionVoter;
|
|
||||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
|
||||||
import org.springframework.security.access.vote.AffirmativeBased;
|
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
|
||||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
|
||||||
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
|
|
||||||
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
|
|
||||||
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
|
|
||||||
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
|
|
||||||
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
|
|
||||||
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
|
|
||||||
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
|
|
||||||
import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor;
|
|
||||||
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
|
|
||||||
import org.springframework.util.AntPathMatcher;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.PathMatcher;
|
|
||||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
|
||||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
|
||||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
|
||||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
|
||||||
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
|
|
||||||
import org.springframework.web.socket.sockjs.SockJsService;
|
|
||||||
import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler;
|
|
||||||
import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows configuring WebSocket Authorization.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* For example:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* @Configuration
|
|
||||||
* public class WebSocketSecurityConfig extends
|
|
||||||
* AbstractSecurityWebSocketMessageBrokerConfigurer {
|
|
||||||
*
|
|
||||||
* @Override
|
|
||||||
* protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
|
||||||
* messages.simpDestMatchers("/user/queue/errors").permitAll()
|
|
||||||
* .simpDestMatchers("/admin/**").hasRole("ADMIN").anyMessage()
|
|
||||||
* .authenticated();
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Rob Winch
|
|
||||||
* @since 4.0
|
|
||||||
* @see WebSocketMessageBrokerSecurityConfiguration
|
|
||||||
* @deprecated Use {@link EnableWebSocketSecurity} instead
|
|
||||||
*/
|
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE + 100)
|
|
||||||
@Import(ObjectPostProcessorConfiguration.class)
|
|
||||||
@Deprecated
|
|
||||||
public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer
|
|
||||||
implements WebSocketMessageBrokerConfigurer, SmartInitializingSingleton {
|
|
||||||
|
|
||||||
private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry();
|
|
||||||
|
|
||||||
private SecurityExpressionHandler<Message<Object>> defaultExpressionHandler = new DefaultMessageSecurityExpressionHandler<>();
|
|
||||||
|
|
||||||
private SecurityExpressionHandler<Message<Object>> expressionHandler;
|
|
||||||
|
|
||||||
private ApplicationContext context;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
|
||||||
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void configureClientInboundChannel(ChannelRegistration registration) {
|
|
||||||
ChannelSecurityInterceptor inboundChannelSecurity = this.context.getBean(ChannelSecurityInterceptor.class);
|
|
||||||
registration.interceptors(this.context.getBean(SecurityContextChannelInterceptor.class));
|
|
||||||
if (!sameOriginDisabled()) {
|
|
||||||
registration.interceptors(this.context.getBean(CsrfChannelInterceptor.class));
|
|
||||||
}
|
|
||||||
if (this.inboundRegistry.containsMapping()) {
|
|
||||||
registration.interceptors(inboundChannelSecurity);
|
|
||||||
}
|
|
||||||
customizeClientInboundChannel(registration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PathMatcher getDefaultPathMatcher() {
|
|
||||||
try {
|
|
||||||
return this.context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher();
|
|
||||||
}
|
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
|
||||||
return new AntPathMatcher();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Determines if a CSRF token is required for connecting. This protects against remote
|
|
||||||
* sites from connecting to the application and being able to read/write data over the
|
|
||||||
* connection. The default is false (the token is required).
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Subclasses can override this method to disable CSRF protection
|
|
||||||
* </p>
|
|
||||||
* @return false if a CSRF token is required for connecting, else true
|
|
||||||
*/
|
|
||||||
protected boolean sameOriginDisabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows subclasses to customize the configuration of the {@link ChannelRegistration}
|
|
||||||
* .
|
|
||||||
* @param registration the {@link ChannelRegistration} to customize
|
|
||||||
*/
|
|
||||||
protected void customizeClientInboundChannel(ChannelRegistration registration) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CsrfChannelInterceptor csrfChannelInterceptor() {
|
|
||||||
return new CsrfChannelInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ChannelSecurityInterceptor inboundChannelSecurity(
|
|
||||||
MessageSecurityMetadataSource messageSecurityMetadataSource) {
|
|
||||||
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
|
|
||||||
messageSecurityMetadataSource);
|
|
||||||
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<>();
|
|
||||||
voter.setExpressionHandler(getMessageExpressionHandler());
|
|
||||||
List<AccessDecisionVoter<?>> voters = new ArrayList<>();
|
|
||||||
voters.add(voter);
|
|
||||||
AffirmativeBased manager = new AffirmativeBased(voters);
|
|
||||||
channelSecurityInterceptor.setAccessDecisionManager(manager);
|
|
||||||
return channelSecurityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SecurityContextChannelInterceptor securityContextChannelInterceptor() {
|
|
||||||
return new SecurityContextChannelInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() {
|
|
||||||
this.inboundRegistry.expressionHandler(getMessageExpressionHandler());
|
|
||||||
configureInbound(this.inboundRegistry);
|
|
||||||
return this.inboundRegistry.createMetadataSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param messages
|
|
||||||
*/
|
|
||||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public void setApplicationContext(ApplicationContext context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setMessageExpessionHandler(List<SecurityExpressionHandler<Message<Object>>> expressionHandlers) {
|
|
||||||
setMessageExpressionHandler(expressionHandlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
public void setMessageExpressionHandler(List<SecurityExpressionHandler<Message<Object>>> expressionHandlers) {
|
|
||||||
if (expressionHandlers.size() == 1) {
|
|
||||||
this.expressionHandler = expressionHandlers.get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
|
||||||
this.defaultExpressionHandler = objectPostProcessor.postProcess(this.defaultExpressionHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecurityExpressionHandler<Message<Object>> getMessageExpressionHandler() {
|
|
||||||
if (this.expressionHandler == null) {
|
|
||||||
return this.defaultExpressionHandler;
|
|
||||||
}
|
|
||||||
return this.expressionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterSingletonsInstantiated() {
|
|
||||||
if (sameOriginDisabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String beanName = "stompWebSocketHandlerMapping";
|
|
||||||
SimpleUrlHandlerMapping mapping = this.context.getBean(beanName, SimpleUrlHandlerMapping.class);
|
|
||||||
Map<String, Object> mappings = mapping.getHandlerMap();
|
|
||||||
for (Object object : mappings.values()) {
|
|
||||||
if (object instanceof SockJsHttpRequestHandler) {
|
|
||||||
setHandshakeInterceptors((SockJsHttpRequestHandler) object);
|
|
||||||
}
|
|
||||||
else if (object instanceof WebSocketHttpRequestHandler) {
|
|
||||||
setHandshakeInterceptors((WebSocketHttpRequestHandler) object);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalStateException("Bean " + beanName + " is expected to contain mappings to either a "
|
|
||||||
+ "SockJsHttpRequestHandler or a WebSocketHttpRequestHandler but got " + object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.inboundRegistry.containsMapping() && !this.inboundRegistry.isSimpDestPathMatcherConfigured()) {
|
|
||||||
PathMatcher pathMatcher = getDefaultPathMatcher();
|
|
||||||
this.inboundRegistry.simpDestPathMatcher(pathMatcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setHandshakeInterceptors(SockJsHttpRequestHandler handler) {
|
|
||||||
SockJsService sockJsService = handler.getSockJsService();
|
|
||||||
Assert.state(sockJsService instanceof TransportHandlingSockJsService,
|
|
||||||
() -> "sockJsService must be instance of TransportHandlingSockJsService got " + sockJsService);
|
|
||||||
TransportHandlingSockJsService transportHandlingSockJsService = (TransportHandlingSockJsService) sockJsService;
|
|
||||||
List<HandshakeInterceptor> handshakeInterceptors = transportHandlingSockJsService.getHandshakeInterceptors();
|
|
||||||
List<HandshakeInterceptor> interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1);
|
|
||||||
interceptorsToSet.add(new CsrfTokenHandshakeInterceptor());
|
|
||||||
interceptorsToSet.addAll(handshakeInterceptors);
|
|
||||||
transportHandlingSockJsService.setHandshakeInterceptors(interceptorsToSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setHandshakeInterceptors(WebSocketHttpRequestHandler handler) {
|
|
||||||
List<HandshakeInterceptor> handshakeInterceptors = handler.getHandshakeInterceptors();
|
|
||||||
List<HandshakeInterceptor> interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1);
|
|
||||||
interceptorsToSet.add(new CsrfTokenHandshakeInterceptor());
|
|
||||||
interceptorsToSet.addAll(handshakeInterceptors);
|
|
||||||
handler.setHandshakeInterceptors(interceptorsToSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MessageSecurityMetadataSource createMetadataSource() {
|
|
||||||
return super.createMetadataSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean containsMapping() {
|
|
||||||
return super.containsMapping();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isSimpDestPathMatcherConfigured() {
|
|
||||||
return super.isSimpDestPathMatcherConfigured();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -31,6 +31,9 @@ final class MessageMatcherAuthorizationManagerConfiguration {
|
||||||
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder(
|
MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder(
|
||||||
ApplicationContext context) {
|
ApplicationContext context) {
|
||||||
MessageMatcherFactory.setApplicationContext(context);
|
MessageMatcherFactory.setApplicationContext(context);
|
||||||
|
if (MessageMatcherFactory.usesPathPatterns()) {
|
||||||
|
return MessageMatcherDelegatingAuthorizationManager.builder();
|
||||||
|
}
|
||||||
return MessageMatcherDelegatingAuthorizationManager.builder()
|
return MessageMatcherDelegatingAuthorizationManager.builder()
|
||||||
.simpDestPathMatcher(
|
.simpDestPathMatcher(
|
||||||
() -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0)
|
() -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0)
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2023 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.config.aot.hint;
|
||||||
|
|
||||||
|
import org.springframework.aot.hint.MemberCategory;
|
||||||
|
import org.springframework.aot.hint.RuntimeHints;
|
||||||
|
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||||
|
import org.springframework.aot.hint.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime hints for
|
||||||
|
* {@link org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration}
|
||||||
|
*
|
||||||
|
* @author Marcus da Coregio
|
||||||
|
*/
|
||||||
|
class WebSecurityConfigurationRuntimeHints implements RuntimeHintsRegistrar {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||||
|
hints.reflection()
|
||||||
|
.registerType(TypeReference
|
||||||
|
.of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy"),
|
||||||
|
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
|
||||||
|
hints.reflection()
|
||||||
|
.registerType(TypeReference.of("org.springframework.web.filter.ServletRequestPathFilter"),
|
||||||
|
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -521,11 +521,23 @@ final class AuthenticationConfigBuilder {
|
||||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||||
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||||
authenticationFilterSecurityContextHolderStrategyRef);
|
authenticationFilterSecurityContextHolderStrategyRef);
|
||||||
String regex = x509Elt.getAttribute("subject-principal-regex");
|
String principalExtractorRef = x509Elt.getAttribute("principal-extractor-ref");
|
||||||
if (StringUtils.hasText(regex)) {
|
String subjectPrincipalRegex = x509Elt.getAttribute("subject-principal-regex");
|
||||||
|
boolean hasPrincipalExtractorRef = StringUtils.hasText(principalExtractorRef);
|
||||||
|
boolean hasSubjectPrincipalRegex = StringUtils.hasText(subjectPrincipalRegex);
|
||||||
|
if (hasPrincipalExtractorRef && hasSubjectPrincipalRegex) {
|
||||||
|
this.pc.getReaderContext()
|
||||||
|
.error("The attribute 'principal-extractor-ref' cannot be used together with the 'subject-principal-regex' attribute within <"
|
||||||
|
+ Elements.X509 + ">", this.pc.extractSource(x509Elt));
|
||||||
|
}
|
||||||
|
if (hasPrincipalExtractorRef) {
|
||||||
|
RuntimeBeanReference principalExtractor = new RuntimeBeanReference(principalExtractorRef);
|
||||||
|
filterBuilder.addPropertyValue("principalExtractor", principalExtractor);
|
||||||
|
}
|
||||||
|
if (hasSubjectPrincipalRegex) {
|
||||||
BeanDefinitionBuilder extractor = BeanDefinitionBuilder
|
BeanDefinitionBuilder extractor = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(SubjectDnX509PrincipalExtractor.class);
|
.rootBeanDefinition(SubjectDnX509PrincipalExtractor.class);
|
||||||
extractor.addPropertyValue("subjectDnRegex", regex);
|
extractor.addPropertyValue("subjectDnRegex", subjectPrincipalRegex);
|
||||||
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
|
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
|
||||||
}
|
}
|
||||||
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
|
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||||
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
|
import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer;
|
||||||
|
import org.springframework.security.web.access.PathPatternRequestTransformer;
|
||||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||||
import org.springframework.security.web.access.channel.InsecureChannelProcessor;
|
import org.springframework.security.web.access.channel.InsecureChannelProcessor;
|
||||||
|
@ -974,10 +975,17 @@ class HttpConfigurationBuilder {
|
||||||
@Override
|
@Override
|
||||||
public AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer getObject()
|
public AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer getObject()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer requestTransformer = this.applicationContext
|
||||||
|
.getBeanProvider(
|
||||||
|
AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer.class)
|
||||||
|
.getIfUnique();
|
||||||
|
if (requestTransformer != null) {
|
||||||
|
return requestTransformer;
|
||||||
|
}
|
||||||
HandlerMappingIntrospector hmi = this.applicationContext.getBeanProvider(HandlerMappingIntrospector.class)
|
HandlerMappingIntrospector hmi = this.applicationContext.getBeanProvider(HandlerMappingIntrospector.class)
|
||||||
.getIfAvailable();
|
.getIfAvailable();
|
||||||
return (hmi != null) ? new HandlerMappingIntrospectorRequestTransformer(hmi)
|
return (hmi != null) ? new HandlerMappingIntrospectorRequestTransformer(hmi)
|
||||||
: AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer.IDENTITY;
|
: new PathPatternRequestTransformer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import org.springframework.beans.BeanMetadataElement;
|
import org.springframework.beans.BeanMetadataElement;
|
||||||
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanReference;
|
import org.springframework.beans.factory.config.BeanReference;
|
||||||
|
@ -40,12 +41,13 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
|
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
|
||||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
|
||||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
|
||||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||||
|
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter;
|
||||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
@ -64,6 +66,8 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||||
|
|
||||||
static final String BEARER_TOKEN_RESOLVER_REF = "bearer-token-resolver-ref";
|
static final String BEARER_TOKEN_RESOLVER_REF = "bearer-token-resolver-ref";
|
||||||
|
|
||||||
|
static final String AUTHENTICATION_CONVERTER_REF = "authentication-converter-ref";
|
||||||
|
|
||||||
static final String ENTRY_POINT_REF = "entry-point-ref";
|
static final String ENTRY_POINT_REF = "entry-point-ref";
|
||||||
|
|
||||||
static final String BEARER_TOKEN_RESOLVER = "bearerTokenResolver";
|
static final String BEARER_TOKEN_RESOLVER = "bearerTokenResolver";
|
||||||
|
@ -124,11 +128,16 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||||
pc.getReaderContext().registerWithGeneratedName(opaqueTokenAuthenticationProvider)));
|
pc.getReaderContext().registerWithGeneratedName(opaqueTokenAuthenticationProvider)));
|
||||||
}
|
}
|
||||||
BeanMetadataElement bearerTokenResolver = getBearerTokenResolver(oauth2ResourceServer);
|
BeanMetadataElement bearerTokenResolver = getBearerTokenResolver(oauth2ResourceServer);
|
||||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
BeanMetadataElement authenticationConverter = getAuthenticationConverter(oauth2ResourceServer);
|
||||||
.rootBeanDefinition(BearerTokenRequestMatcher.class);
|
if (bearerTokenResolver != null && authenticationConverter != null) {
|
||||||
requestMatcherBuilder.addConstructorArgValue(bearerTokenResolver);
|
throw new BeanDefinitionStoreException(
|
||||||
BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
|
"You cannot use bearer-token-ref and authentication-converter-ref in the same oauth2-resource-server element");
|
||||||
|
}
|
||||||
|
if (bearerTokenResolver == null && authenticationConverter == null) {
|
||||||
|
authenticationConverter = new RootBeanDefinition(BearerTokenAuthenticationConverter.class);
|
||||||
|
}
|
||||||
BeanMetadataElement authenticationEntryPoint = getEntryPoint(oauth2ResourceServer);
|
BeanMetadataElement authenticationEntryPoint = getEntryPoint(oauth2ResourceServer);
|
||||||
|
BeanDefinition requestMatcher = buildRequestMatcher(bearerTokenResolver, authenticationConverter);
|
||||||
this.entryPoints.put(requestMatcher, authenticationEntryPoint);
|
this.entryPoints.put(requestMatcher, authenticationEntryPoint);
|
||||||
this.deniedHandlers.put(requestMatcher, this.accessDeniedHandler);
|
this.deniedHandlers.put(requestMatcher, this.accessDeniedHandler);
|
||||||
this.ignoreCsrfRequestMatchers.add(requestMatcher);
|
this.ignoreCsrfRequestMatchers.add(requestMatcher);
|
||||||
|
@ -136,13 +145,35 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||||
.rootBeanDefinition(BearerTokenAuthenticationFilter.class);
|
.rootBeanDefinition(BearerTokenAuthenticationFilter.class);
|
||||||
BeanMetadataElement authenticationManagerResolver = getAuthenticationManagerResolver(oauth2ResourceServer);
|
BeanMetadataElement authenticationManagerResolver = getAuthenticationManagerResolver(oauth2ResourceServer);
|
||||||
filterBuilder.addConstructorArgValue(authenticationManagerResolver);
|
filterBuilder.addConstructorArgValue(authenticationManagerResolver);
|
||||||
filterBuilder.addPropertyValue(BEARER_TOKEN_RESOLVER, bearerTokenResolver);
|
|
||||||
filterBuilder.addPropertyValue(AUTHENTICATION_ENTRY_POINT, authenticationEntryPoint);
|
filterBuilder.addPropertyValue(AUTHENTICATION_ENTRY_POINT, authenticationEntryPoint);
|
||||||
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||||
this.authenticationFilterSecurityContextHolderStrategy);
|
this.authenticationFilterSecurityContextHolderStrategy);
|
||||||
|
|
||||||
|
if (authenticationConverter != null) {
|
||||||
|
filterBuilder.addConstructorArgValue(authenticationConverter);
|
||||||
|
}
|
||||||
|
if (bearerTokenResolver != null) {
|
||||||
|
filterBuilder.addPropertyValue(BEARER_TOKEN_RESOLVER, bearerTokenResolver);
|
||||||
|
}
|
||||||
return filterBuilder.getBeanDefinition();
|
return filterBuilder.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BeanDefinition buildRequestMatcher(BeanMetadataElement bearerTokenResolver,
|
||||||
|
BeanMetadataElement authenticationConverter) {
|
||||||
|
if (bearerTokenResolver != null) {
|
||||||
|
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(BearerTokenRequestMatcher.class);
|
||||||
|
requestMatcherBuilder.addConstructorArgValue(bearerTokenResolver);
|
||||||
|
return requestMatcherBuilder.getBeanDefinition();
|
||||||
|
}
|
||||||
|
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(BearerTokenAuthenticationRequestMatcher.class);
|
||||||
|
if (authenticationConverter != null) {
|
||||||
|
requestMatcherBuilder.addConstructorArgValue(authenticationConverter);
|
||||||
|
}
|
||||||
|
return requestMatcherBuilder.getBeanDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
void validateConfiguration(Element oauth2ResourceServer, Element jwt, Element opaqueToken, ParserContext pc) {
|
void validateConfiguration(Element oauth2ResourceServer, Element jwt, Element opaqueToken, ParserContext pc) {
|
||||||
if (!oauth2ResourceServer.hasAttribute(AUTHENTICATION_MANAGER_RESOLVER_REF)) {
|
if (!oauth2ResourceServer.hasAttribute(AUTHENTICATION_MANAGER_RESOLVER_REF)) {
|
||||||
if (jwt == null && opaqueToken == null) {
|
if (jwt == null && opaqueToken == null) {
|
||||||
|
@ -178,11 +209,19 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||||
BeanMetadataElement getBearerTokenResolver(Element element) {
|
BeanMetadataElement getBearerTokenResolver(Element element) {
|
||||||
String bearerTokenResolverRef = element.getAttribute(BEARER_TOKEN_RESOLVER_REF);
|
String bearerTokenResolverRef = element.getAttribute(BEARER_TOKEN_RESOLVER_REF);
|
||||||
if (!StringUtils.hasLength(bearerTokenResolverRef)) {
|
if (!StringUtils.hasLength(bearerTokenResolverRef)) {
|
||||||
return new RootBeanDefinition(DefaultBearerTokenResolver.class);
|
return null;
|
||||||
}
|
}
|
||||||
return new RuntimeBeanReference(bearerTokenResolverRef);
|
return new RuntimeBeanReference(bearerTokenResolverRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BeanMetadataElement getAuthenticationConverter(Element element) {
|
||||||
|
String authenticationConverterRef = element.getAttribute(AUTHENTICATION_CONVERTER_REF);
|
||||||
|
if (!StringUtils.hasLength(authenticationConverterRef)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new RuntimeBeanReference(authenticationConverterRef);
|
||||||
|
}
|
||||||
|
|
||||||
BeanMetadataElement getEntryPoint(Element element) {
|
BeanMetadataElement getEntryPoint(Element element) {
|
||||||
String entryPointRef = element.getAttribute(ENTRY_POINT_REF);
|
String entryPointRef = element.getAttribute(ENTRY_POINT_REF);
|
||||||
if (!StringUtils.hasLength(entryPointRef)) {
|
if (!StringUtils.hasLength(entryPointRef)) {
|
||||||
|
@ -300,7 +339,7 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||||
String clientId = element.getAttribute(CLIENT_ID);
|
String clientId = element.getAttribute(CLIENT_ID);
|
||||||
String clientSecret = element.getAttribute(CLIENT_SECRET);
|
String clientSecret = element.getAttribute(CLIENT_SECRET);
|
||||||
BeanDefinitionBuilder introspectorBuilder = BeanDefinitionBuilder
|
BeanDefinitionBuilder introspectorBuilder = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(NimbusOpaqueTokenIntrospector.class);
|
.rootBeanDefinition(SpringOpaqueTokenIntrospector.class);
|
||||||
introspectorBuilder.addConstructorArgValue(introspectionUri);
|
introspectorBuilder.addConstructorArgValue(introspectionUri);
|
||||||
introspectorBuilder.addConstructorArgValue(clientId);
|
introspectorBuilder.addConstructorArgValue(clientId);
|
||||||
introspectorBuilder.addConstructorArgValue(clientSecret);
|
introspectorBuilder.addConstructorArgValue(clientSecret);
|
||||||
|
@ -366,4 +405,29 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class BearerTokenAuthenticationRequestMatcher implements RequestMatcher {
|
||||||
|
|
||||||
|
private final AuthenticationConverter authenticationConverter;
|
||||||
|
|
||||||
|
BearerTokenAuthenticationRequestMatcher() {
|
||||||
|
this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
BearerTokenAuthenticationRequestMatcher(AuthenticationConverter authenticationConverter) {
|
||||||
|
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||||
|
this.authenticationConverter = authenticationConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
return this.authenticationConverter.convert(request) != null;
|
||||||
|
}
|
||||||
|
catch (OAuth2AuthenticationException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||||
|
import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor;
|
||||||
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
|
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
|
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter;
|
||||||
|
@ -239,7 +241,13 @@ final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
if (authentication == null) {
|
if (authentication == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal;
|
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return authentication instanceof Saml2Authentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
|
||||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
@ -47,7 +46,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
private static final String CONTEXT_SOURCE_CLASS = "org.springframework.security.ldap.DefaultSpringSecurityContextSource";
|
private static final String CONTEXT_SOURCE_CLASS = "org.springframework.security.ldap.DefaultSpringSecurityContextSource";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the Url of the ldap server to use. If not specified, an embedded apache DS
|
* Defines the Url of the ldap server to use. If not specified, an embedded UnboundID
|
||||||
* instance will be created
|
* instance will be created
|
||||||
*/
|
*/
|
||||||
private static final String ATT_URL = "url";
|
private static final String ATT_URL = "url";
|
||||||
|
@ -78,22 +77,15 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
private static final int DEFAULT_PORT = 33389;
|
private static final int DEFAULT_PORT = 33389;
|
||||||
|
|
||||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
|
||||||
|
|
||||||
private static final String UNBOUNID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
private static final String UNBOUNID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||||
|
|
||||||
private static final String APACHEDS_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.ApacheDSContainer";
|
|
||||||
|
|
||||||
private static final String UNBOUNDID_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.UnboundIdContainer";
|
private static final String UNBOUNDID_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.UnboundIdContainer";
|
||||||
|
|
||||||
private static final boolean unboundIdPresent;
|
private static final boolean unboundIdPresent;
|
||||||
|
|
||||||
private static final boolean apacheDsPresent;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ClassLoader classLoader = LdapServerBeanDefinitionParser.class.getClassLoader();
|
ClassLoader classLoader = LdapServerBeanDefinitionParser.class.getClassLoader();
|
||||||
unboundIdPresent = ClassUtils.isPresent(UNBOUNID_CLASSNAME, classLoader);
|
unboundIdPresent = ClassUtils.isPresent(UNBOUNID_CLASSNAME, classLoader);
|
||||||
apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,10 +120,9 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
/**
|
/**
|
||||||
* Will be called if no url attribute is supplied.
|
* Will be called if no url attribute is supplied.
|
||||||
*
|
*
|
||||||
* Registers beans to create an embedded apache directory server.
|
* Registers beans to create an embedded UnboundID Server.
|
||||||
* @return the BeanDefinition for the ContextSource for the embedded server.
|
* @return the BeanDefinition for the ContextSource for the embedded server.
|
||||||
*
|
*
|
||||||
* @see ApacheDSContainer
|
|
||||||
* @see UnboundIdContainer
|
* @see UnboundIdContainer
|
||||||
*/
|
*/
|
||||||
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
|
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
|
||||||
|
@ -162,8 +153,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
}
|
}
|
||||||
ldapContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
|
ldapContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
|
||||||
ldapContainer.getPropertyValues().addPropertyValue("port", getPort(element));
|
ldapContainer.getPropertyValues().addPropertyValue("port", getPort(element));
|
||||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_APACHE_DS)
|
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_UNBOUNDID)) {
|
||||||
|| parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_UNBOUNDID)) {
|
|
||||||
parserContext.getReaderContext()
|
parserContext.getReaderContext()
|
||||||
.error("Only one embedded server bean is allowed per application context", element);
|
.error("Only one embedded server bean is allowed per application context", element);
|
||||||
}
|
}
|
||||||
|
@ -175,9 +165,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RootBeanDefinition getRootBeanDefinition(String mode) {
|
private RootBeanDefinition getRootBeanDefinition(String mode) {
|
||||||
if (isApacheDsEnabled(mode)) {
|
|
||||||
return new RootBeanDefinition(APACHEDS_CONTAINER_CLASSNAME, null, null);
|
|
||||||
}
|
|
||||||
if (isUnboundidEnabled(mode)) {
|
if (isUnboundidEnabled(mode)) {
|
||||||
return new RootBeanDefinition(UNBOUNDID_CONTAINER_CLASSNAME, null, null);
|
return new RootBeanDefinition(UNBOUNDID_CONTAINER_CLASSNAME, null, null);
|
||||||
}
|
}
|
||||||
|
@ -185,19 +172,12 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveBeanId(String mode) {
|
private String resolveBeanId(String mode) {
|
||||||
if (isApacheDsEnabled(mode)) {
|
|
||||||
return BeanIds.EMBEDDED_APACHE_DS;
|
|
||||||
}
|
|
||||||
if (isUnboundidEnabled(mode)) {
|
if (isUnboundidEnabled(mode)) {
|
||||||
return BeanIds.EMBEDDED_UNBOUNDID;
|
return BeanIds.EMBEDDED_UNBOUNDID;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isApacheDsEnabled(String mode) {
|
|
||||||
return "apacheds".equals(mode) || apacheDsPresent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isUnboundidEnabled(String mode) {
|
private boolean isUnboundidEnabled(String mode) {
|
||||||
return "unboundid".equals(mode) || unboundIdPresent;
|
return "unboundid".equals(mode) || unboundIdPresent;
|
||||||
}
|
}
|
||||||
|
@ -233,10 +213,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPort() {
|
private int getPort() {
|
||||||
if (apacheDsPresent) {
|
|
||||||
ApacheDSContainer apacheDSContainer = this.applicationContext.getBean(ApacheDSContainer.class);
|
|
||||||
return apacheDSContainer.getLocalPort();
|
|
||||||
}
|
|
||||||
if (unboundIdPresent) {
|
if (unboundIdPresent) {
|
||||||
UnboundIdContainer unboundIdContainer = this.applicationContext.getBean(UnboundIdContainer.class);
|
UnboundIdContainer unboundIdContainer = this.applicationContext.getBean(UnboundIdContainer.class);
|
||||||
return unboundIdContainer.getPort();
|
return unboundIdContainer.getPort();
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.springframework.security.access.AccessDecisionVoter;
|
||||||
import org.springframework.security.access.vote.AffirmativeBased;
|
import org.springframework.security.access.vote.AffirmativeBased;
|
||||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||||
import org.springframework.security.access.vote.RoleVoter;
|
import org.springframework.security.access.vote.RoleVoter;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +33,9 @@ import org.springframework.security.config.BeanIds;
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
|
* @deprecated Please use {@link AuthorizationManager} instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
abstract class MethodConfigUtils {
|
abstract class MethodConfigUtils {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2020 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -125,7 +125,7 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini
|
||||||
getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_SECRET))
|
getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_SECRET))
|
||||||
.ifPresent(builder::clientSecret);
|
.ifPresent(builder::clientSecret);
|
||||||
getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_AUTHENTICATION_METHOD))
|
getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_AUTHENTICATION_METHOD))
|
||||||
.map(ClientAuthenticationMethod::new)
|
.map(ClientAuthenticationMethod::valueOf)
|
||||||
.ifPresent(builder::clientAuthenticationMethod);
|
.ifPresent(builder::clientAuthenticationMethod);
|
||||||
getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_AUTHORIZATION_GRANT_TYPE))
|
getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_AUTHORIZATION_GRANT_TYPE))
|
||||||
.map(AuthorizationGrantType::new)
|
.map(AuthorizationGrantType::new)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue