Compare commits

..

No commits in common. "main" and "6.5.0-RC1" have entirely different histories.

981 changed files with 14271 additions and 17257 deletions

40
.github/dependabot.template.yml vendored Normal file
View File

@ -0,0 +1,40 @@
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/*"

View File

@ -4,32 +4,6 @@ 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: /
@ -111,8 +85,17 @@ 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: /
@ -123,6 +106,14 @@ 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: /

View File

@ -1,17 +0,0 @@
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

View File

@ -39,25 +39,48 @@ jobs:
toolchain: 17 toolchain: 17
with: with:
java-version: ${{ matrix.java-version }} java-version: ${{ matrix.java-version }}
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.2.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2024.0.+ --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] needs: [ build, test, check-samples ]
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 ] needs: [ build, test, check-samples ]
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 ] needs: [ build, test, check-samples ]
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 }}

View File

@ -0,0 +1,57 @@
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'

View File

@ -4,8 +4,7 @@ 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

View File

@ -0,0 +1,45 @@
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

View File

@ -0,0 +1,63 @@
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 }}

View File

@ -11,7 +11,7 @@ jobs:
strategy: strategy:
matrix: matrix:
# List of active maintenance branches. # List of active maintenance branches.
branch: [ main, 6.5.x, 6.4.x, 6.3.x ] branch: [ main, 6.4.x, 6.3.x ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout

View File

@ -0,0 +1,22 @@
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

36
.github/workflows/update-dependabot.yml vendored Normal file
View File

@ -0,0 +1,36 @@
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

View File

@ -79,9 +79,6 @@ 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.
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`. To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
[[submit-a-pull-request]] [[submit-a-pull-request]]

View File

@ -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, List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
(rs, rowNum) -> mapObjectIdentityRow(rs), args); (rs, rowNum) -> mapObjectIdentityRow(rs));
return (!objects.isEmpty()) ? objects : null; return (!objects.isEmpty()) ? objects : null;
} }

View File

@ -190,7 +190,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 createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) { protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type); List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, new Object[] { type },
Long.class);
if (!classIds.isEmpty()) { if (!classIds.isEmpty()) {
return classIds.get(0); return classIds.get(0);
@ -241,8 +242,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, Long.class, sidIsPrincipal, List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey,
sidName); new Object[] { sidIsPrincipal, sidName }, Long.class);
if (!sidIds.isEmpty()) { if (!sidIds.isEmpty()) {
return sidIds.get(0); return sidIds.get(0);
} }

View File

@ -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(), any(RowMapper.class), eq(args))).willReturn(result); given(this.jdbcOperations.query(anyString(), eq(args), any(RowMapper.class))).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);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2024 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('A')") @PreAuthorize("hasRole('X')")
void publicCallsPrivate() { void publicCallsPrivate() {
privateMethod(); privateMethod();
} }

View File

@ -1,6 +1,5 @@
plugins { plugins {
id "java-gradle-plugin" id "java-gradle-plugin"
id "groovy-gradle-plugin"
id "java" id "java"
id "groovy" id "groovy"
} }
@ -77,7 +76,6 @@ 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'
} }

View File

@ -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())
); );
})); }));
}); });
@ -71,4 +71,4 @@ public class ManagementConfigurationPlugin implements Plugin<Project> {
})); }));
}); });
} }
} }

View File

@ -80,11 +80,6 @@ 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
}
}
} }
} }

View File

@ -32,13 +32,10 @@ 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(schemaResourceName) it.path.endsWith(schemas.get(key))
}
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

View File

@ -1,17 +0,0 @@
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'
}
}
})

View File

@ -81,6 +81,9 @@ 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;
} }

View File

@ -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));

View File

@ -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: 'security-kotlin' apply plugin: 'kotlin'
configurations { configurations {
opensaml5 { opensaml5 {
@ -78,6 +78,12 @@ 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"
@ -121,7 +127,6 @@ 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)
@ -153,6 +158,15 @@ 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

View File

@ -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.UnboundIdContainer; import org.springframework.security.ldap.server.ApacheDSContainer;
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
UnboundIdContainer ldapServer() throws Exception { ApacheDSContainer ldapServer() throws Exception {
UnboundIdContainer unboundIdContainer = new UnboundIdContainer("dc=springframework,dc=org", ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org",
"classpath:/test-server.ldif"); "classpath:/test-server.ldif");
unboundIdContainer.setPort(getPort()); apacheDSContainer.setPort(getPort());
return unboundIdContainer; return apacheDSContainer;
} }
} }

View File

@ -74,7 +74,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -87,7 +87,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -74,7 +74,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -86,7 +86,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -81,7 +81,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -79,7 +79,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -79,7 +79,8 @@ 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) -> registry.forSocketAcceptor(this.interceptor) .interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
) )
.acceptor(this.handler.responder()) .acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0)) .bind(TcpServerTransport.create("localhost", 0))

View File

@ -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.UnboundIdContainer; import org.springframework.security.ldap.server.ApacheDSContainer;
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 UnboundIdContainer container; private ApacheDSContainer container;
@Bean @Bean
UnboundIdContainer ldapServer() { ApacheDSContainer ldapServer() throws Exception {
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); this.container = new ApacheDSContainer("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(UnboundIdContainer container) { BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
int port = container.getPort(); int port = container.getLocalPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org"); return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
} }

View File

@ -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.UnboundIdContainer; import org.springframework.security.ldap.server.ApacheDSContainer;
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 UnboundIdContainer container; private ApacheDSContainer container;
@Bean @Bean
UnboundIdContainer ldapServer() { ApacheDSContainer ldapServer() throws Exception {
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); this.container = new ApacheDSContainer("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(UnboundIdContainer container) { BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
int port = container.getPort(); int port = container.getLocalPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org"); return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
} }

View File

@ -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("otherben", "otherbenspassword")); .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
UserDetails ben = (UserDetails) auth.getPrincipal(); UserDetails ben = (UserDetails) auth.getPrincipal();
assertThat(ben.getAuthorities()).hasSize(3); assertThat(ben.getAuthorities()).hasSize(3);
} }
@ -127,27 +127,6 @@ 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(

View File

@ -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.UnboundIdContainer; import org.springframework.security.ldap.server.ApacheDSContainer;
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/>");
UnboundIdContainer dsContainer = this.appCtx.getBean(UnboundIdContainer.class); ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class);
assertThat(ReflectionTestUtils.getField(dsContainer, "ldif")).isEqualTo("classpath*:*.ldif"); assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif");
} }
private int getDefaultPort() throws IOException { private int getDefaultPort() throws IOException {

View File

@ -7,6 +7,7 @@
<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"/>

View File

@ -54,6 +54,8 @@ 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";

View File

@ -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 7.0. Please update your schema declarations to the 7.0 schema.", + "with Spring Security 6.5. Please update your schema declarations to the 6.5 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-7\\.0.*.xsd.*") return schemaLocation.matches("(?m).*spring-security-6\\.5.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*") || schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*"); || !schemaLocation.matches("(?m).*spring-security.*");
} }

View File

@ -50,6 +50,17 @@ 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}

View File

@ -67,7 +67,9 @@ public class AuthenticationManagerBuilder
/** /**
* Creates a new instance * Creates a new instance
* @param objectPostProcessor the {@link ObjectPostProcessor} instance to use. * @param objectPostProcessor the
* {@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);

View File

@ -25,6 +25,7 @@ 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;
@ -37,6 +38,7 @@ 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;
@ -59,8 +61,12 @@ 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";
@ -95,6 +101,7 @@ 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);
} }
@ -126,7 +133,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 LdapAuthenticationProviderConfigurer} for further customizations * @return the {@link ChannelSecurityConfigurer} for further customizations
*/ */
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) { public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor); addObjectPostProcessor(objectPostProcessor);
@ -386,10 +393,6 @@ 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());
@ -465,6 +468,8 @@ 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;
@ -580,8 +585,14 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return contextSource; return contextSource;
} }
private void startEmbeddedLdapServer() { private void startEmbeddedLdapServer() throws Exception {
if (unboundIdPresent) { if (apacheDsPresent) {
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);

View File

@ -41,8 +41,4 @@ public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuild
super(new InMemoryUserDetailsManager(new ArrayList<>())); super(new InMemoryUserDetailsManager(new ArrayList<>()));
} }
public B and() {
return getBuilder();
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2024 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,22 +16,13 @@
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)
@ -43,45 +34,4 @@ 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;
}
}
} }

View File

@ -16,30 +16,20 @@
package org.springframework.security.config.annotation.method.configuration; package org.springframework.security.config.annotation.method.configuration;
import java.util.List;
import java.util.Map; import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
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.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; 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.ModelAndView;
import org.springframework.web.servlet.View; import org.springframework.web.servlet.View;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
@Configuration @Configuration
class AuthorizationProxyWebConfiguration implements WebMvcConfigurer { class AuthorizationProxyWebConfiguration {
@Bean @Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ -47,21 +37,7 @@ class AuthorizationProxyWebConfiguration implements WebMvcConfigurer {
return new WebTargetVisitor(); return new WebTargetVisitor();
} }
@Override static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor {
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 @Override
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
@ -75,7 +51,7 @@ class AuthorizationProxyWebConfiguration implements WebMvcConfigurer {
if (target instanceof ModelAndView mav) { if (target instanceof ModelAndView mav) {
View view = mav.getView(); View view = mav.getView();
String viewName = mav.getViewName(); String viewName = mav.getViewName();
Map<String, Object> model = proxyFactory.proxy(mav.getModel()); Map<String, Object> model = (Map<String, Object>) proxyFactory.proxy(mav.getModel());
ModelAndView proxied = (view != null) ? new ModelAndView(view, model) ModelAndView proxied = (view != null) ? new ModelAndView(view, model)
: new ModelAndView(viewName, model); : new ModelAndView(viewName, model);
proxied.setStatus(mav.getStatus()); proxied.setStatus(mav.getStatus());
@ -84,31 +60,6 @@ class AuthorizationProxyWebConfiguration implements WebMvcConfigurer {
return null; 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;
}
} }
} }

View File

@ -0,0 +1,72 @@
/*
* 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);
}
}

View File

@ -0,0 +1,73 @@
/*
* 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);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2024 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,11 +83,10 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration
private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor; private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
ReactiveAuthorizationManagerMethodSecurityConfiguration( @Autowired(required = false)
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlers, ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler,
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);

View File

@ -33,16 +33,12 @@ 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.

View File

@ -41,6 +41,7 @@ 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;
@ -169,7 +170,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 AbstractRequestMatcherRegistry} * {@link AbstractConfigAttributeRequestMatcherRegistry}
* @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}
*/ */

View File

@ -385,8 +385,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
if (filter instanceof AuthorizationFilter authorization) { if (filter instanceof AuthorizationFilter authorization) {
AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager(); AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager();
builder.add(securityFilterChain::matches, builder.add(securityFilterChain::matches,
(authentication, context) -> (AuthorizationDecision) authorizationManager (authentication, context) -> authorizationManager.check(authentication, context.getRequest()));
.authorize(authentication, context.getRequest()));
mappings = true; mappings = true;
} }
} }

View File

@ -46,9 +46,8 @@ import org.springframework.security.web.SecurityFilterChain;
* *
* &#064;Bean * &#064;Bean
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
* http.authorizeHttpRequests((authorize) -&gt; authorize * http.authorizeHttpRequests().requestMatchers(&quot;/public/**&quot;).permitAll().anyRequest()
* .requestMatchers(&quot;/public/**&quot;).permitAll() * .hasRole(&quot;USER&quot;).and()
* .anyRequest().hasRole(&quot;USER&quot;))
* // 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

View File

@ -21,7 +21,6 @@ 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;
@ -58,7 +57,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#anonymous(Customizer) * @see HttpSecurity#anonymous()
*/ */
public AnonymousConfigurer() { public AnonymousConfigurer() {
} }

View File

@ -231,6 +231,17 @@ 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();
}
} }
/** /**

View File

@ -24,7 +24,10 @@ 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;
@ -93,7 +96,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#requiresChannel(Customizer) * @see HttpSecurity#requiresChannel()
*/ */
public ChannelSecurityConfigurer(ApplicationContext context) { public ChannelSecurityConfigurer(ApplicationContext context) {
this.REGISTRY = new ChannelRequestMatcherRegistry(context); this.REGISTRY = new ChannelRequestMatcherRegistry(context);
@ -204,6 +207,18 @@ 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();
}
} }
/** /**

View File

@ -18,7 +18,6 @@ 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;
@ -58,7 +57,7 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
/** /**
* Creates a new instance * Creates a new instance
* *
* @see HttpSecurity#cors(Customizer) * @see HttpSecurity#cors()
*/ */
public CorsConfigurer() { public CorsConfigurer() {
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2023 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,15 +19,12 @@ 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;
@ -37,17 +34,13 @@ 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;
@ -55,7 +48,6 @@ 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
@ -104,7 +96,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#csrf(Customizer) * @see HttpSecurity#csrf()
*/ */
public CsrfConfigurer(ApplicationContext context) { public CsrfConfigurer(ApplicationContext context) {
this.context = context; this.context = context;
@ -164,16 +156,16 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* *
* <pre> * <pre>
* http * http
* .csrf((csrf) -&gt; csrf * .csrf()
* .ignoringRequestMatchers((request) -&gt; "XMLHttpRequest".equals(request.getHeader("X-Requested-With")))) * .ignoringRequestMatchers((request) -&gt; "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) {
new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers); return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers).and();
return this;
} }
/** /**
@ -192,8 +184,9 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* *
* <pre> * <pre>
* http * http
* .csrf((csrf) -&gt; csrf * .csrf()
* .ignoringRequestMatchers("/sockjs/**")) * .ignoringRequestMatchers("/sockjs/**")
* .and()
* ... * ...
* </pre> * </pre>
* *
@ -201,8 +194,7 @@ 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) {
new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns); return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns).and();
return this;
} }
/** /**
@ -222,21 +214,6 @@ 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) {
@ -386,6 +363,10 @@ 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);
@ -394,27 +375,4 @@ 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);
}
}
} }

View File

@ -33,6 +33,13 @@ 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
@ -51,6 +58,8 @@ 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>

View File

@ -18,7 +18,6 @@ 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;
@ -77,7 +76,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#exceptionHandling(Customizer) * @see HttpSecurity#exceptionHandling()
*/ */
public ExceptionHandlingConfigurer() { public ExceptionHandlingConfigurer() {
} }

View File

@ -29,7 +29,6 @@ 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;
@ -78,7 +77,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(Customizer) * @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
* @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead * @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead
*/ */
@Deprecated @Deprecated
@ -105,7 +104,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#authorizeRequests(Customizer) * @see HttpSecurity#authorizeRequests()
*/ */
public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) { public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class) GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class)
@ -251,7 +250,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
} }
public H and() { public H and() {
return ExpressionUrlAuthorizationConfigurer.this.getBuilder(); return ExpressionUrlAuthorizationConfigurer.this.and();
} }
} }

View File

@ -17,7 +17,6 @@
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;
@ -75,7 +74,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#formLogin(Customizer) * @see HttpSecurity#formLogin()
*/ */
public FormLoginConfigurer() { public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(), null); super(new UsernamePasswordAuthenticationFilter(), null);

View File

@ -111,7 +111,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* *
* @see HttpSecurity#headers(Customizer) * @see HttpSecurity#headers()
*/ */
public HeadersConfigurer() { public HeadersConfigurer() {
} }
@ -127,6 +127,26 @@ 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"
@ -144,6 +164,26 @@ 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>
* *
@ -161,6 +201,26 @@ 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:
@ -178,6 +238,19 @@ 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
@ -191,6 +264,20 @@ 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
@ -202,6 +289,21 @@ 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>.
@ -218,6 +320,39 @@ 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
@ -319,6 +454,71 @@ 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
@ -368,6 +568,35 @@ 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
@ -414,6 +643,26 @@ 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">
@ -438,6 +687,26 @@ 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">
@ -462,6 +731,26 @@ 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">
@ -500,6 +789,17 @@ 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;
} }
@ -564,6 +864,21 @@ 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;
} }
@ -597,6 +912,21 @@ 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
@ -694,6 +1024,18 @@ 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
@ -721,7 +1063,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 HeadersConfigurer.this; return and();
} }
/** /**
@ -735,7 +1077,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 HeadersConfigurer.this; return and();
} }
/** /**
@ -744,6 +1086,20 @@ 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;
} }
@ -961,6 +1317,18 @@ 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 {
@ -981,6 +1349,18 @@ 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 {
@ -1019,6 +1399,18 @@ 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 {
@ -1040,6 +1432,18 @@ 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 {
@ -1062,6 +1466,18 @@ 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 {
@ -1084,6 +1500,18 @@ 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;
}
} }
} }

View File

@ -26,7 +26,6 @@ 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;
@ -99,7 +98,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#httpBasic(Customizer) * @see HttpSecurity#httpBasic()
*/ */
public HttpBasicConfigurer() { public HttpBasicConfigurer() {
realmName(DEFAULT_REALM); realmName(DEFAULT_REALM);

View File

@ -22,7 +22,6 @@ 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;
@ -78,7 +77,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends Abstr
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#jee(Customizer) * @see HttpSecurity#jee()
*/ */
public JeeConfigurer() { public JeeConfigurer() {
} }

View File

@ -23,7 +23,6 @@ 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;
@ -93,7 +92,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#logout(Customizer) * @see HttpSecurity#logout()
*/ */
public LogoutConfigurer() { public LogoutConfigurer() {
} }
@ -151,7 +150,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(Customizer) * @see HttpSecurity#csrf()
*/ */
public LogoutConfigurer<H> logoutUrl(String logoutUrl) { public LogoutConfigurer<H> logoutUrl(String logoutUrl) {
this.logoutRequestMatcher = null; this.logoutRequestMatcher = null;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2024 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,9 +145,6 @@ 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) {
@ -159,7 +156,6 @@ 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);
} }

View File

@ -16,7 +16,6 @@
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;
@ -71,7 +70,7 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#securityContext(Customizer) * @see HttpSecurity#securityContext()
*/ */
public SecurityContextConfigurer() { public SecurityContextConfigurer() {
} }

View File

@ -23,7 +23,6 @@ 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;
@ -67,7 +66,7 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#servletApi(Customizer) * @see HttpSecurity#servletApi()
*/ */
public ServletApiConfigurer() { public ServletApiConfigurer() {
} }

View File

@ -152,7 +152,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#sessionManagement(Customizer) * @see HttpSecurity#sessionManagement()
*/ */
public SessionManagementConfigurer() { public SessionManagementConfigurer() {
} }
@ -775,6 +775,17 @@ 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;
}
} }
} }

View File

@ -248,7 +248,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
} }
public H and() { public H and() {
return UrlAuthorizationConfigurer.this.getBuilder(); return UrlAuthorizationConfigurer.this.and();
} }
} }

View File

@ -46,7 +46,6 @@ 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
@ -76,7 +75,6 @@ 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;
} }
@ -87,7 +85,6 @@ 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;
} }
@ -109,7 +106,6 @@ 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;
} }
@ -133,7 +129,6 @@ 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;
} }
@ -145,15 +140,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) UserDetailsService userDetailsService = getSharedOrBean(http, UserDetailsService.class).orElseGet(() -> {
.orElseThrow(() -> new IllegalStateException("Missing UserDetailsService Bean")); throw new IllegalStateException("Missing UserDetailsService Bean");
});
PublicKeyCredentialUserEntityRepository userEntities = getSharedOrBean(http, PublicKeyCredentialUserEntityRepository userEntities = getSharedOrBean(http,
PublicKeyCredentialUserEntityRepository.class) PublicKeyCredentialUserEntityRepository.class)
.orElse(userEntityRepository()); .orElse(userEntityRepository());
@ -243,9 +238,12 @@ 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);
return webauthnOperationsBean.orElseGet(() -> new Webauthn4JRelyingPartyOperations(userEntities, if (webauthnOperationsBean.isPresent()) {
userCredentials, PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(), return webauthnOperationsBean.get();
this.allowedOrigins)); }
Webauthn4JRelyingPartyOperations result = new Webauthn4JRelyingPartyOperations(userEntities, userCredentials,
PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(), this.allowedOrigins);
return result;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2024 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,7 +21,6 @@ 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;
@ -91,7 +90,7 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* *
* @see HttpSecurity#x509(Customizer) * @see HttpSecurity#x509()
*/ */
public X509Configurer() { public X509Configurer() {
} }
@ -162,10 +161,7 @@ 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);

View File

@ -141,6 +141,18 @@ 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
@ -230,6 +242,17 @@ 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());

View File

@ -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(Customizer) * @see HttpSecurity#oauth2Login()
* @see OAuth2AuthorizationRequestRedirectFilter * @see OAuth2AuthorizationRequestRedirectFilter
* @see OAuth2LoginAuthenticationFilter * @see OAuth2LoginAuthenticationFilter
* @see ClientRegistrationRepository * @see ClientRegistrationRepository
@ -246,6 +246,18 @@ 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
@ -258,6 +270,21 @@ 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
@ -270,6 +297,18 @@ 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
@ -282,6 +321,21 @@ 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
@ -350,9 +404,11 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper);
oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper);
} }
http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); oidcAuthorizationCodeAuthenticationProvider = this.postProcess(oidcAuthorizationCodeAuthenticationProvider);
http.authenticationProvider(oidcAuthorizationCodeAuthenticationProvider);
registerDelegateApplicationListener(this.postProcess(oidcAuthorizedClientRefreshedEventListener)); oidcAuthorizedClientRefreshedEventListener = this.postProcess(oidcAuthorizedClientRefreshedEventListener);
registerDelegateApplicationListener(oidcAuthorizedClientRefreshedEventListener);
configureOidcUserRefreshedEventListener(http); configureOidcUserRefreshedEventListener(http);
} }
else { else {
@ -668,6 +724,17 @@ 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;
}
} }
/** /**
@ -694,6 +761,20 @@ 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;
}
} }
/** /**
@ -718,6 +799,17 @@ 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;
}
} }
/** /**
@ -772,6 +864,17 @@ 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 {

View File

@ -18,6 +18,11 @@ 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;
@ -33,7 +38,6 @@ 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;
@ -63,10 +67,8 @@ 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(type, new OidcBackChannelLogoutTokenValidator(clientRegistration)); .createDefaultWithValidators(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)) {
@ -77,7 +79,11 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio
null); null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
} }
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build(); JOSEObjectTypeVerifier<SecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(null,
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;

View File

@ -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
.fromUriString(UrlUtils.buildFullRequestUrl(request)) .fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
.replacePath(request.getContextPath()) .replacePath(request.getContextPath())
.replaceQuery(null) .replaceQuery(null)
.fragment(null) .fragment(null)

View File

@ -111,6 +111,11 @@ 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) {

View File

@ -29,7 +29,6 @@ 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;
@ -52,19 +51,11 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR
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> {
@ -80,7 +71,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(getTokenAuthenticationManager(http))); http.authenticationProvider(new DPoPAuthenticationProvider(authenticationManager));
AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager, AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager,
getAuthenticationConverter()); getAuthenticationConverter());
authenticationFilter.setRequestMatcher(getRequestMatcher()); authenticationFilter.setRequestMatcher(getRequestMatcher());
@ -91,23 +82,6 @@ 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();

View File

@ -37,7 +37,6 @@ 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;
@ -50,14 +49,13 @@ 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;
@ -158,7 +156,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver; private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
private AuthenticationConverter authenticationConverter; private BearerTokenResolver bearerTokenResolver;
private JwtConfigurer jwtConfigurer; private JwtConfigurer jwtConfigurer;
@ -198,20 +196,22 @@ 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.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver); this.bearerTokenResolver = bearerTokenResolver;
return this; return this;
} }
/** /**
* Sets the {@link AuthenticationConverter} to use. * @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
* @param authenticationConverter the authentication converter * {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
* @return the {@link OAuth2ResourceServerConfigurer} for further configuration * "https://docs.spring.io/spring-security/reference/migration-7/configuration.html#_use_the_lambda_dsl">documentation</a>
* @since 7.0 * for more details.
*/ */
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) { @Deprecated(since = "6.1", forRemoval = true)
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); public JwtConfigurer jwt() {
this.authenticationConverter = authenticationConverter; if (this.jwtConfigurer == null) {
return this; this.jwtConfigurer = new JwtConfigurer(this.context);
}
return this.jwtConfigurer;
} }
/** /**
@ -228,6 +228,21 @@ 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
@ -256,15 +271,16 @@ 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;
} }
AuthenticationConverter converter = getAuthenticationConverter(); BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
this.requestMatcher.setAuthenticationConverter(converter); filter.setBearerTokenResolver(bearerTokenResolver);
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);
@ -347,33 +363,16 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
return http.getSharedObject(AuthenticationManager.class); return http.getSharedObject(AuthenticationManager.class);
} }
AuthenticationManagerResolver<HttpServletRequest> getAuthenticationManagerResolver() {
return this.authenticationManagerResolver;
}
AuthenticationConverter getAuthenticationConverter() {
if (this.authenticationConverter != null) {
return this.authenticationConverter;
}
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() { BearerTokenResolver getBearerTokenResolver() {
AuthenticationConverter authenticationConverter = getAuthenticationConverter(); if (this.bearerTokenResolver == null) {
if (authenticationConverter instanceof OAuth2ResourceServerConfigurer.BearerTokenResolverHoldingAuthenticationConverter bearer) { if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
return bearer.bearerTokenResolver; this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
}
else {
this.bearerTokenResolver = new DefaultBearerTokenResolver();
}
} }
return null; return this.bearerTokenResolver;
} }
public class JwtConfigurer { public class JwtConfigurer {
@ -412,6 +411,17 @@ 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) {
@ -550,41 +560,21 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
private static final class BearerTokenRequestMatcher implements RequestMatcher { private static final class BearerTokenRequestMatcher implements RequestMatcher {
private AuthenticationConverter authenticationConverter; private BearerTokenResolver bearerTokenResolver;
@Override @Override
public boolean matches(HttpServletRequest request) { public boolean matches(HttpServletRequest request) {
try { try {
return this.authenticationConverter.convert(request) != null; return this.bearerTokenResolver.resolve(request) != null;
} }
catch (OAuth2AuthenticationException ex) { catch (OAuth2AuthenticationException ex) {
return false; return false;
} }
} }
void setAuthenticationConverter(AuthenticationConverter authenticationConverter) { void setBearerTokenResolver(BearerTokenResolver tokenResolver) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); Assert.notNull(tokenResolver, "resolver cannot be null");
this.authenticationConverter = authenticationConverter; this.bearerTokenResolver = tokenResolver;
}
}
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);
} }
} }

View File

@ -27,7 +27,6 @@ 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;
@ -112,7 +111,7 @@ import org.springframework.util.StringUtils;
* </ul> * </ul>
* *
* @since 5.2 * @since 5.2
* @see HttpSecurity#saml2Login(Customizer) * @see HttpSecurity#saml2Login()
* @see Saml2WebSsoAuthenticationFilter * @see Saml2WebSsoAuthenticationFilter
* @see Saml2WebSsoAuthenticationRequestFilter * @see Saml2WebSsoAuthenticationRequestFilter
* @see RelyingPartyRegistrationRepository * @see RelyingPartyRegistrationRepository

View File

@ -34,8 +34,6 @@ 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;
@ -135,7 +133,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
/** /**
* Creates a new instance * Creates a new instance
* @see HttpSecurity#logout(Customizer) * @see HttpSecurity#logout()
*/ */
public Saml2LogoutConfigurer(ApplicationContext context) { public Saml2LogoutConfigurer(ApplicationContext context) {
this.context = context; this.context = context;
@ -158,7 +156,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(Customizer) * @see HttpSecurity#csrf()
*/ */
public Saml2LogoutConfigurer<H> logoutUrl(String logoutUrl) { public Saml2LogoutConfigurer<H> logoutUrl(String logoutUrl) {
this.logoutUrl = logoutUrl; this.logoutUrl = logoutUrl;
@ -177,6 +175,20 @@ 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
@ -189,6 +201,20 @@ 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
@ -378,6 +404,18 @@ 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;
@ -448,6 +486,18 @@ 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;
@ -484,13 +534,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
if (authentication == null) { if (authentication == null) {
return false; return false;
} }
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal;
return true;
}
if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor) {
return true;
}
return authentication instanceof Saml2Authentication;
} }
} }

View File

@ -43,8 +43,6 @@ 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
@ -158,8 +156,8 @@ class ServerHttpSecurityConfiguration {
ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity(); ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity();
// @formatter:off // @formatter:off
return http.authenticationManager(authenticationManager()) return http.authenticationManager(authenticationManager())
.headers(withDefaults()) .headers().and()
.logout(withDefaults()); .logout().and();
// @formatter:on // @formatter:on
} }

View File

@ -40,8 +40,6 @@ 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
@ -123,13 +121,13 @@ class WebFluxSecurityConfiguration {
* @return * @return
*/ */
private SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { private SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); http.authorizeExchange().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(withDefaults()); http.httpBasic();
http.formLogin(withDefaults()); http.formLogin();
} }
SecurityWebFilterChain result = http.build(); SecurityWebFilterChain result = http.build();
return result; return result;
@ -138,8 +136,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(withDefaults()); http.oauth2Login();
http.oauth2Client(withDefaults()); http.oauth2Client();
} }
static boolean shouldConfigure(ApplicationContext context) { static boolean shouldConfigure(ApplicationContext context) {

View File

@ -0,0 +1,286 @@
/*
* 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>
* &#064;Configuration
* public class WebSocketSecurityConfig extends
* AbstractSecurityWebSocketMessageBrokerConfigurer {
*
* &#064;Override
* protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
* messages.simpDestMatchers(&quot;/user/queue/errors&quot;).permitAll()
* .simpDestMatchers(&quot;/admin/**&quot;).hasRole(&quot;ADMIN&quot;).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();
}
}
}

View File

@ -31,9 +31,6 @@ 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)

View File

@ -521,23 +521,11 @@ final class AuthenticationConfigBuilder {
filterBuilder.addPropertyValue("authenticationManager", authManager); filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("securityContextHolderStrategy", filterBuilder.addPropertyValue("securityContextHolderStrategy",
authenticationFilterSecurityContextHolderStrategyRef); authenticationFilterSecurityContextHolderStrategyRef);
String principalExtractorRef = x509Elt.getAttribute("principal-extractor-ref"); String regex = x509Elt.getAttribute("subject-principal-regex");
String subjectPrincipalRegex = x509Elt.getAttribute("subject-principal-regex"); if (StringUtils.hasText(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", subjectPrincipalRegex); extractor.addPropertyValue("subjectDnRegex", regex);
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition()); filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
} }
injectAuthenticationDetailsSource(x509Elt, filterBuilder); injectAuthenticationDetailsSource(x509Elt, filterBuilder);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2022 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,7 +23,6 @@ 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;
@ -41,13 +40,12 @@ 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.SpringOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
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;
@ -66,8 +64,6 @@ 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";
@ -128,16 +124,11 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
pc.getReaderContext().registerWithGeneratedName(opaqueTokenAuthenticationProvider))); pc.getReaderContext().registerWithGeneratedName(opaqueTokenAuthenticationProvider)));
} }
BeanMetadataElement bearerTokenResolver = getBearerTokenResolver(oauth2ResourceServer); BeanMetadataElement bearerTokenResolver = getBearerTokenResolver(oauth2ResourceServer);
BeanMetadataElement authenticationConverter = getAuthenticationConverter(oauth2ResourceServer); BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
if (bearerTokenResolver != null && authenticationConverter != null) { .rootBeanDefinition(BearerTokenRequestMatcher.class);
throw new BeanDefinitionStoreException( requestMatcherBuilder.addConstructorArgValue(bearerTokenResolver);
"You cannot use bearer-token-ref and authentication-converter-ref in the same oauth2-resource-server element"); BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
}
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);
@ -145,35 +136,13 @@ 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) {
@ -209,19 +178,11 @@ 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 null; return new RootBeanDefinition(DefaultBearerTokenResolver.class);
} }
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)) {
@ -339,7 +300,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(SpringOpaqueTokenIntrospector.class); .rootBeanDefinition(NimbusOpaqueTokenIntrospector.class);
introspectorBuilder.addConstructorArgValue(introspectionUri); introspectorBuilder.addConstructorArgValue(introspectionUri);
introspectorBuilder.addConstructorArgValue(clientId); introspectorBuilder.addConstructorArgValue(clientId);
introspectorBuilder.addConstructorArgValue(clientSecret); introspectorBuilder.addConstructorArgValue(clientSecret);
@ -405,29 +366,4 @@ 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;
}
}
}
} }

View File

@ -32,8 +32,6 @@ 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;
@ -241,13 +239,7 @@ final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser {
if (authentication == null) { if (authentication == null) {
return false; return false;
} }
if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { return 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) {

View File

@ -32,6 +32,7 @@ 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;
@ -46,7 +47,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 UnboundID * Defines the Url of the ldap server to use. If not specified, an embedded apache DS
* instance will be created * instance will be created
*/ */
private static final String ATT_URL = "url"; private static final String ATT_URL = "url";
@ -77,15 +78,22 @@ 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
@ -120,9 +128,10 @@ 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 UnboundID Server. * Registers beans to create an embedded apache directory 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) {
@ -153,7 +162,8 @@ 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_UNBOUNDID)) { if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_APACHE_DS)
|| 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);
} }
@ -165,6 +175,9 @@ 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);
} }
@ -172,12 +185,19 @@ 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;
} }
@ -213,6 +233,10 @@ 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();

View File

@ -24,7 +24,6 @@ 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;
/** /**
@ -33,9 +32,7 @@ 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")

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2022 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,7 +16,6 @@
package org.springframework.security.config.oauth2.client; package org.springframework.security.config.oauth2.client;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
@ -28,7 +27,7 @@ import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
* Common OAuth2 Providers that can be used to create * Common OAuth2 Providers that can be used to create
* {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder
* builders} pre-configured with sensible defaults for the * builders} pre-configured with sensible defaults for the
* {@link HttpSecurity#oauth2Login(Customizer)} flow. * {@link HttpSecurity#oauth2Login()} flow.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 5.0 * @since 5.0
@ -88,23 +87,6 @@ public enum CommonOAuth2Provider {
}, },
X {
@Override
public Builder getBuilder(String registrationId) {
ClientRegistration.Builder builder = getBuilder(registrationId,
ClientAuthenticationMethod.CLIENT_SECRET_POST, DEFAULT_REDIRECT_URL);
builder.scope("users.read", "tweet.read");
builder.authorizationUri("https://x.com/i/oauth2/authorize");
builder.tokenUri("https://api.x.com/2/oauth2/token");
builder.userInfoUri("https://api.x.com/2/users/me");
builder.userNameAttributeName("username");
builder.clientName("X");
return builder;
}
},
OKTA { OKTA {
@Override @Override

View File

@ -18,6 +18,10 @@ package org.springframework.security.config.web.server;
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.JWKSecurityContext;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
@ -37,7 +41,6 @@ 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.NimbusReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
@ -69,10 +72,8 @@ final class OidcBackChannelLogoutReactiveAuthenticationManager implements Reacti
* Construct an {@link OidcBackChannelLogoutReactiveAuthenticationManager} * Construct an {@link OidcBackChannelLogoutReactiveAuthenticationManager}
*/ */
OidcBackChannelLogoutReactiveAuthenticationManager() { OidcBackChannelLogoutReactiveAuthenticationManager() {
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(type, new OidcBackChannelLogoutTokenValidator(clientRegistration)); .createDefaultWithValidators(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)) {
@ -83,7 +84,11 @@ final class OidcBackChannelLogoutReactiveAuthenticationManager implements Reacti
null); null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
} }
NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build(); JOSEObjectTypeVerifier<JWKSecurityContext> typeVerifier = new DefaultJOSEObjectTypeVerifier<>(null,
JOSEObjectType.JWT, new JOSEObjectType("logout+jwt"));
NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
.jwtProcessorCustomizer((processor) -> processor.setJWSTypeVerifier(typeVerifier))
.build();
decoder.setJwtValidator(jwtValidator.apply(clientRegistration)); decoder.setJwtValidator(jwtValidator.apply(clientRegistration));
decoder.setClaimSetConverter( decoder.setClaimSetConverter(
new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters())); new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters()));

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2023 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.
@ -18,12 +18,12 @@ package org.springframework.security.config.web.server;
import java.util.Collections; import java.util.Collections;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.codec.EncoderHttpMessageWriter; import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter;
@ -47,7 +47,6 @@ import org.springframework.web.server.WebFilterChain;
* A filter for the Client-side OIDC Back-Channel Logout endpoint * A filter for the Client-side OIDC Back-Channel Logout endpoint
* *
* @author Josh Cummings * @author Josh Cummings
* @author Andrey Litvitski
* @since 6.2 * @since 6.2
* @see <a target="_blank" href= * @see <a target="_blank" href=
* "https://openid.net/specs/openid-connect-backchannel-1_0.html">OIDC Back-Channel Logout * "https://openid.net/specs/openid-connect-backchannel-1_0.html">OIDC Back-Channel Logout
@ -109,7 +108,7 @@ class OidcBackChannelLogoutWebFilter implements WebFilter {
private Mono<Void> handleAuthenticationFailure(ServerWebExchange exchange, Exception ex) { private Mono<Void> handleAuthenticationFailure(ServerWebExchange exchange, Exception ex) {
this.logger.debug("Failed to process OIDC Back-Channel Logout", ex); this.logger.debug("Failed to process OIDC Back-Channel Logout", ex);
exchange.getResponse().setRawStatusCode(HttpStatus.BAD_REQUEST.value()); exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_BAD_REQUEST);
return this.errorHttpMessageConverter.write(Mono.just(oauth2Error(ex)), ResolvableType.forClass(Object.class), return this.errorHttpMessageConverter.write(Mono.just(oauth2Error(ex)), ResolvableType.forClass(Object.class),
ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(), ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(),
exchange.getResponse(), Collections.emptyMap()); exchange.getResponse(), Collections.emptyMap());

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2024 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.
@ -22,13 +22,13 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.EncoderHttpMessageWriter; import org.springframework.http.codec.EncoderHttpMessageWriter;
@ -54,8 +54,7 @@ import org.springframework.web.util.UriComponentsBuilder;
* Back-Channel Logout Token and invalidates each one. * Back-Channel Logout Token and invalidates each one.
* *
* @author Josh Cummings * @author Josh Cummings
* @author Andrey Litvitski * @since 6.4
* @since 6.2
* @see <a target="_blank" href= * @see <a target="_blank" href=
* "https://openid.net/specs/openid-connect-backchannel-1_0.html">OIDC Back-Channel Logout * "https://openid.net/specs/openid-connect-backchannel-1_0.html">OIDC Back-Channel Logout
* Spec</a> * Spec</a>
@ -171,7 +170,7 @@ public final class OidcBackChannelServerLogoutHandler implements ServerLogoutHan
} }
private Mono<Void> handleLogoutFailure(ServerWebExchange exchange, OAuth2Error error) { private Mono<Void> handleLogoutFailure(ServerWebExchange exchange, OAuth2Error error) {
exchange.getResponse().setRawStatusCode(HttpStatus.BAD_REQUEST.value()); exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_BAD_REQUEST);
return this.errorHttpMessageConverter.write(Mono.just(error), ResolvableType.forClass(Object.class), return this.errorHttpMessageConverter.write(Mono.just(error), ResolvableType.forClass(Object.class),
ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(), ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(),
exchange.getResponse(), Collections.emptyMap()); exchange.getResponse(), Collections.emptyMap());

View File

@ -16,13 +16,9 @@
package org.springframework.security.config.websocket; package org.springframework.security.config.websocket;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@ -311,11 +307,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
private static final String TEMPLATE_EXPRESSION_BEAN_ID = "annotationExpressionTemplateDefaults"; private static final String TEMPLATE_EXPRESSION_BEAN_ID = "annotationExpressionTemplateDefaults";
private static final Set<String> CSRF_HANDSHAKE_HANDLER_CLASSES = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList("org.springframework.web.socket.server.support.WebSocketHttpRequestHandler",
"org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService",
"org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService")));
private final String inboundSecurityInterceptorId; private final String inboundSecurityInterceptorId;
private final boolean sameOriginDisabled; private final boolean sameOriginDisabled;
@ -354,7 +345,16 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
} }
} }
} }
else if (CSRF_HANDSHAKE_HANDLER_CLASSES.contains(beanClassName)) { else if ("org.springframework.web.socket.server.support.WebSocketHttpRequestHandler"
.equals(beanClassName)) {
addCsrfTokenHandshakeInterceptor(bd);
}
else if ("org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService"
.equals(beanClassName)) {
addCsrfTokenHandshakeInterceptor(bd);
}
else if ("org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService"
.equals(beanClassName)) {
addCsrfTokenHandshakeInterceptor(bd); addCsrfTokenHandshakeInterceptor(bd);
} }
} }

View File

@ -51,7 +51,6 @@ class X509Dsl {
var authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails>? = null var authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails>? = null
var userDetailsService: UserDetailsService? = null var userDetailsService: UserDetailsService? = null
var authenticationUserDetailsService: AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken>? = null var authenticationUserDetailsService: AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken>? = null
@Deprecated("Use x509PrincipalExtractor instead")
var subjectPrincipalRegex: String? = null var subjectPrincipalRegex: String? = null

View File

@ -14,8 +14,7 @@
# limitations under the License. # limitations under the License.
# #
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.5.xsd
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
http\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd http\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd
http\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd http\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd
@ -42,8 +41,7 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.5.xsd
https\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd
https\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd https\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd

Some files were not shown because too many files have changed in this diff Show More