Compare commits

..

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

1213 changed files with 15095 additions and 25014 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

View File

@ -18,7 +18,7 @@ jobs:
matrix: matrix:
branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ] branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ]
steps: steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0 - uses: spring-io/spring-doc-actions/update-antora-spring-ui@852920ba3fb1f28b35a2f13201133bc00ef33677
name: Update name: Update
with: with:
docs-branch: ${{ matrix.branch }} docs-branch: ${{ matrix.branch }}
@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Update on docs-build name: Update on docs-build
steps: steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0 - uses: spring-io/spring-doc-actions/update-antora-spring-ui@852920ba3fb1f28b35a2f13201133bc00ef33677
name: Update name: Update
with: with:
docs-branch: 'docs-build' docs-branch: 'docs-build'

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,10 +79,7 @@ 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. To format the code as well as check the style, run `./gradlew format check`.
The team may ask you to change to a `for` loop if the given code is along a hot path.
To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
[[submit-a-pull-request]] [[submit-a-pull-request]]
=== Submit a Pull Request === Submit a Pull Request
@ -107,7 +104,7 @@ If this is for an issue, consider a branch name with the issue number, like `gh-
6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year. 6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds 7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`. 8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
9. [[format-code]] For each commit, build the code using `./gradlew format && ./gradlew check`. 9. [[format-code]] For each commit, build the code using `./gradlew format check`.
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order. This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent 10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent
multiple edits or corrections of the same logical change. multiple edits or corrections of the same logical change.

View File

@ -96,11 +96,7 @@ import org.springframework.util.StringUtils;
* All comparisons and prefixes are case sensitive. * All comparisons and prefixes are case sensitive.
* *
* @author Ben Alex * @author Ben Alex
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
* annotations may also prove useful, for example
* {@code @PreAuthorize("hasPermission(#id, ObjectsReturnType.class, read)")}
*/ */
@Deprecated
public class AclEntryVoter extends AbstractAclVoter { public class AclEntryVoter extends AbstractAclVoter {
private static final Log logger = LogFactory.getLog(AclEntryVoter.class); private static final Log logger = LogFactory.getLog(AclEntryVoter.class);

View File

@ -20,7 +20,6 @@ import java.util.List;
import org.springframework.security.access.AfterInvocationProvider; import org.springframework.security.access.AfterInvocationProvider;
import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl; import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl; import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
import org.springframework.security.acls.model.Acl; import org.springframework.security.acls.model.Acl;
@ -40,11 +39,7 @@ import org.springframework.util.ObjectUtils;
* services. * services.
* *
* @author Ben Alex * @author Ben Alex
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
* annotations may also prove useful, for example
* {@code @PostAuthorize("hasPermission(filterObject, read)")}
*/ */
@Deprecated
public abstract class AbstractAclProvider implements AfterInvocationProvider { public abstract class AbstractAclProvider implements AfterInvocationProvider {
protected final AclService aclService; protected final AclService aclService;

View File

@ -26,7 +26,6 @@ import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException; import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.model.AclService; import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.Permission; import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -63,11 +62,7 @@ import org.springframework.security.core.Authentication;
* *
* @author Ben Alex * @author Ben Alex
* @author Paulo Neves * @author Paulo Neves
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
* annotations may also prove useful, for example
* {@code @PostFilter("hasPermission(filterObject, read)")}
*/ */
@Deprecated
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider { public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class); protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);

View File

@ -27,7 +27,6 @@ import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor; import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.model.AclService; import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.Permission; import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -60,12 +59,7 @@ import org.springframework.security.core.SpringSecurityMessageSource;
* granted and <code>null</code> will be returned. * granted and <code>null</code> will be returned.
* <p> * <p>
* All comparisons and prefixes are case sensitive. * All comparisons and prefixes are case sensitive.
*
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
* annotations may also prove useful, for example
* {@code @PostAuthorize("hasPermission(filterObject, read)")}
*/ */
@Deprecated
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware { public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class); protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);

View File

@ -32,9 +32,7 @@ import org.springframework.core.log.LogMessage;
* *
* @author Ben Alex * @author Ben Alex
* @author Paulo Neves * @author Paulo Neves
* @deprecated please see {@code PostFilter}
*/ */
@Deprecated
class ArrayFilterer<T> implements Filterer<T> { class ArrayFilterer<T> implements Filterer<T> {
protected static final Log logger = LogFactory.getLog(ArrayFilterer.class); protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);

View File

@ -31,9 +31,7 @@ import org.springframework.core.log.LogMessage;
* *
* @author Ben Alex * @author Ben Alex
* @author Paulo Neves * @author Paulo Neves
* @deprecated please see {@code PostFilter}
*/ */
@Deprecated
class CollectionFilterer<T> implements Filterer<T> { class CollectionFilterer<T> implements Filterer<T> {
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class); protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);

View File

@ -23,9 +23,7 @@ import java.util.Iterator;
* *
* @author Ben Alex * @author Ben Alex
* @author Paulo Neves * @author Paulo Neves
* @deprecated please use {@code PreFilter} and {@code @PostFilter} instead
*/ */
@Deprecated
interface Filterer<T> extends Iterable<T> { interface Filterer<T> extends Iterable<T> {
/** /**

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

@ -124,7 +124,7 @@ wrapperUpgrade {
gradle { gradle {
'spring-security' { 'spring-security' {
repo = 'spring-projects/spring-security' repo = 'spring-projects/spring-security'
baseBranch = '6.3.x' // runs only on 6.3.x and the update is merged forward to main baseBranch = '6.2.x' // runs only on 6.2.x and the update is merged forward to main
} }
} }
} }

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())
); );
})); }));
}); });

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

@ -51,7 +51,6 @@ import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
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;
@ -216,8 +215,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
public CasAuthenticationFilter() { public CasAuthenticationFilter() {
super("/login/cas"); super("/login/cas");
RequestMatcher processUri = PathPatternRequestMatcher.withDefaults().matcher("/login/cas");
setRequiresAuthenticationRequestMatcher(processUri);
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler()); setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
setSecurityContextRepository(this.securityContextRepository); setSecurityContextRepository(this.securityContextRepository);
} }
@ -322,18 +319,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
super.setAuthenticationFailureHandler(new CasAuthenticationFailureHandler(failureHandler)); super.setAuthenticationFailureHandler(new CasAuthenticationFailureHandler(failureHandler));
} }
/**
* Use this {@code RequestMatcher} to match proxy receptor requests. Without setting
* this matcher, {@link CasAuthenticationFilter} will not capture any proxy receptor
* requets.
* @param proxyReceptorMatcher the {@link RequestMatcher} to use
* @since 6.5
*/
public final void setProxyReceptorMatcher(RequestMatcher proxyReceptorMatcher) {
Assert.notNull(proxyReceptorMatcher, "proxyReceptorMatcher cannot be null");
this.proxyReceptorMatcher = proxyReceptorMatcher;
}
public final void setProxyReceptorUrl(final String proxyReceptorUrl) { public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl); this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
} }

View File

@ -43,7 +43,6 @@ import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
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;
@ -79,7 +78,7 @@ public class CasAuthenticationFilterTests {
@Test @Test
public void testNormalOperation() throws Exception { public void testNormalOperation() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/login/cas"); MockHttpServletRequest request = new MockHttpServletRequest();
request.setServletPath("/login/cas"); request.setServletPath("/login/cas");
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ"); request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
CasAuthenticationFilter filter = new CasAuthenticationFilter(); CasAuthenticationFilter filter = new CasAuthenticationFilter();
@ -104,7 +103,7 @@ public class CasAuthenticationFilterTests {
String url = "/login/cas"; String url = "/login/cas";
CasAuthenticationFilter filter = new CasAuthenticationFilter(); CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setFilterProcessesUrl(url); filter.setFilterProcessesUrl(url);
MockHttpServletRequest request = new MockHttpServletRequest("POST", url); MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
request.setServletPath(url); request.setServletPath(url);
assertThat(filter.requiresAuthentication(request, response)).isTrue(); assertThat(filter.requiresAuthentication(request, response)).isTrue();
@ -133,11 +132,10 @@ public class CasAuthenticationFilterTests {
CasAuthenticationFilter filter = new CasAuthenticationFilter(); CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setFilterProcessesUrl(url); filter.setFilterProcessesUrl(url);
filter.setServiceProperties(properties); filter.setServiceProperties(properties);
MockHttpServletRequest request = new MockHttpServletRequest("POST", url); MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
request.setServletPath(url); request.setServletPath(url);
assertThat(filter.requiresAuthentication(request, response)).isTrue(); assertThat(filter.requiresAuthentication(request, response)).isTrue();
request = new MockHttpServletRequest("POST", "/other");
request.setServletPath("/other"); request.setServletPath("/other");
assertThat(filter.requiresAuthentication(request, response)).isFalse(); assertThat(filter.requiresAuthentication(request, response)).isFalse();
request.setParameter(properties.getArtifactParameter(), "value"); request.setParameter(properties.getArtifactParameter(), "value");
@ -172,7 +170,7 @@ public class CasAuthenticationFilterTests {
given(manager.authenticate(any(Authentication.class))).willReturn(authentication); given(manager.authenticate(any(Authentication.class))).willReturn(authentication);
ServiceProperties serviceProperties = new ServiceProperties(); ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true); serviceProperties.setAuthenticateAllArtifacts(true);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/authenticate"); MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("ticket", "ST-1-123"); request.setParameter("ticket", "ST-1-123");
request.setServletPath("/authenticate"); request.setServletPath("/authenticate");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
@ -268,20 +266,4 @@ public class CasAuthenticationFilterTests {
verify(securityContextRepository).setContext(any(SecurityContext.class)); verify(securityContextRepository).setContext(any(SecurityContext.class));
} }
@Test
public void requiresAuthenticationWhenProxyRequestMatcherThenMatches() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/pgtCallback");
MockHttpServletResponse response = new MockHttpServletResponse();
request.setServletPath("/pgtCallback");
assertThat(filter.requiresAuthentication(request, response)).isFalse();
filter.setProxyReceptorMatcher(PathPatternRequestMatcher.withDefaults().matcher(request.getServletPath()));
assertThat(filter.requiresAuthentication(request, response)).isFalse();
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
assertThat(filter.requiresAuthentication(request, response)).isTrue();
request.setRequestURI("/other");
request.setServletPath("/other");
assertThat(filter.requiresAuthentication(request, response)).isFalse();
}
} }

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

@ -17,7 +17,6 @@
package org.springframework.security.config.annotation.method.configuration; package org.springframework.security.config.annotation.method.configuration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
@ -32,7 +31,6 @@ import org.springframework.security.aot.hint.SecurityHintsRegistrar;
import org.springframework.security.authorization.AuthorizationProxyFactory; import org.springframework.security.authorization.AuthorizationProxyFactory;
import org.springframework.security.authorization.method.AuthorizationAdvisor; import org.springframework.security.authorization.method.AuthorizationAdvisor;
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor;
import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor;
import org.springframework.security.config.Customizer; import org.springframework.security.config.Customizer;
@ -42,23 +40,21 @@ final class AuthorizationProxyConfiguration implements AopInfrastructureBean {
@Bean @Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static AuthorizationAdvisorProxyFactory authorizationProxyFactory( static AuthorizationAdvisorProxyFactory authorizationProxyFactory(
ObjectProvider<AuthorizationAdvisor> authorizationAdvisors, ObjectProvider<TargetVisitor> targetVisitors,
ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) { ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) {
List<AuthorizationAdvisor> advisors = new ArrayList<>(); AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(new ArrayList<>());
authorizationAdvisors.forEach(advisors::add);
List<TargetVisitor> visitors = new ArrayList<>();
targetVisitors.orderedStream().forEach(visitors::add);
visitors.add(TargetVisitor.defaults());
AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(advisors);
factory.setTargetVisitor(TargetVisitor.of(visitors.toArray(TargetVisitor[]::new)));
customizers.forEach((c) -> c.customize(factory)); customizers.forEach((c) -> c.customize(factory));
return factory; return factory;
} }
@Bean @Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor authorizeReturnObjectMethodInterceptor() { static MethodInterceptor authorizeReturnObjectMethodInterceptor(ObjectProvider<AuthorizationAdvisor> provider,
return new AuthorizeReturnObjectMethodInterceptor(); AuthorizationAdvisorProxyFactory authorizationProxyFactory) {
provider.forEach(authorizationProxyFactory::addAdvisor);
AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor(
authorizationProxyFactory);
authorizationProxyFactory.addAdvisor(interceptor);
return interceptor;
} }
@Bean @Bean

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

@ -1,114 +0,0 @@
/*
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.Ordered;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
@Configuration
class AuthorizationProxyWebConfiguration implements WebMvcConfigurer {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
AuthorizationAdvisorProxyFactory.TargetVisitor webTargetVisitor() {
return new WebTargetVisitor();
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
for (int i = 0; i < resolvers.size(); i++) {
HandlerExceptionResolver resolver = resolvers.get(i);
if (resolver instanceof DefaultHandlerExceptionResolver) {
resolvers.add(i, new AccessDeniedExceptionResolver());
return;
}
}
resolvers.add(new AccessDeniedExceptionResolver());
}
static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered {
private static final int DEFAULT_ORDER = 100;
@Override
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
if (target instanceof ResponseEntity<?> entity) {
return new ResponseEntity<>(proxyFactory.proxy(entity.getBody()), entity.getHeaders(),
entity.getStatusCode());
}
if (target instanceof HttpEntity<?> entity) {
return new HttpEntity<>(proxyFactory.proxy(entity.getBody()), entity.getHeaders());
}
if (target instanceof ModelAndView mav) {
View view = mav.getView();
String viewName = mav.getViewName();
Map<String, Object> model = proxyFactory.proxy(mav.getModel());
ModelAndView proxied = (view != null) ? new ModelAndView(view, model)
: new ModelAndView(viewName, model);
proxied.setStatus(mav.getStatus());
return proxied;
}
return null;
}
@Override
public int getOrder() {
return DEFAULT_ORDER;
}
}
static class AccessDeniedExceptionResolver implements HandlerExceptionResolver {
final ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer();
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);
Throwable accessDeniedException = this.throwableAnalyzer
.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
if (accessDeniedException != null) {
return new ModelAndView((model, req, res) -> {
throw ex;
});
}
return null;
}
}
}

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.
@ -41,9 +41,6 @@ final class MethodSecuritySelector implements ImportSelector {
private static final boolean isDataPresent = ClassUtils private static final boolean isDataPresent = ClassUtils
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null); .isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
private static final boolean isWebPresent = ClassUtils
.isPresent("org.springframework.web.servlet.DispatcherServlet", null);
private static final boolean isObservabilityPresent = ClassUtils private static final boolean isObservabilityPresent = ClassUtils
.isPresent("io.micrometer.observation.ObservationRegistry", null); .isPresent("io.micrometer.observation.ObservationRegistry", null);
@ -70,9 +67,6 @@ final class MethodSecuritySelector implements ImportSelector {
if (isDataPresent) { if (isDataPresent) {
imports.add(AuthorizationProxyDataConfiguration.class.getName()); imports.add(AuthorizationProxyDataConfiguration.class.getName());
} }
if (isWebPresent) {
imports.add(AuthorizationProxyWebConfiguration.class.getName());
}
if (isObservabilityPresent) { if (isObservabilityPresent) {
imports.add(MethodObservationConfiguration.class.getName()); imports.add(MethodObservationConfiguration.class.getName());
} }

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

@ -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.
@ -38,9 +38,6 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
private static final boolean isDataPresent = ClassUtils private static final boolean isDataPresent = ClassUtils
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null); .isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
private static final boolean isWebPresent = ClassUtils.isPresent("org.springframework.web.server.ServerWebExchange",
null);
private static final boolean isObservabilityPresent = ClassUtils private static final boolean isObservabilityPresent = ClassUtils
.isPresent("io.micrometer.observation.ObservationRegistry", null); .isPresent("io.micrometer.observation.ObservationRegistry", null);
@ -64,9 +61,6 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
if (isDataPresent) { if (isDataPresent) {
imports.add(AuthorizationProxyDataConfiguration.class.getName()); imports.add(AuthorizationProxyDataConfiguration.class.getName());
} }
if (isWebPresent) {
imports.add(AuthorizationProxyWebConfiguration.class.getName());
}
if (isObservabilityPresent) { if (isObservabilityPresent) {
imports.add(ReactiveMethodObservationConfiguration.class.getName()); imports.add(ReactiveMethodObservationConfiguration.class.getName());
} }

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

@ -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.
@ -135,7 +135,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* <li>{@link DisableEncodeUrlFilter}</li> * <li>{@link DisableEncodeUrlFilter}</li>
* <li>{@link ForceEagerSessionCreationFilter}</li> * <li>{@link ForceEagerSessionCreationFilter}</li>
* <li>{@link ChannelProcessingFilter}</li> * <li>{@link ChannelProcessingFilter}</li>
* <li>{@link org.springframework.security.web.transport.HttpsRedirectFilter}</li>
* <li>{@link WebAsyncManagerIntegrationFilter}</li> * <li>{@link WebAsyncManagerIntegrationFilter}</li>
* <li>{@link SecurityContextHolderFilter}</li> * <li>{@link SecurityContextHolderFilter}</li>
* <li>{@link SecurityContextPersistenceFilter}</li> * <li>{@link SecurityContextPersistenceFilter}</li>

View File

@ -35,9 +35,7 @@ import org.springframework.core.ResolvableType;
import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.SingleResultAuthorizationManager;
import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.ObjectPostProcessor;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder; import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
import org.springframework.security.config.annotation.SecurityBuilder; import org.springframework.security.config.annotation.SecurityBuilder;
@ -60,8 +58,6 @@ import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
import org.springframework.security.web.debug.DebugFilter; import org.springframework.security.web.debug.DebugFilter;
import org.springframework.security.web.firewall.CompositeRequestRejectedHandler; import org.springframework.security.web.firewall.CompositeRequestRejectedHandler;
import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.HttpFirewall;
@ -69,7 +65,6 @@ import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandle
import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler; import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler;
import org.springframework.security.web.firewall.RequestRejectedHandler; import org.springframework.security.web.firewall.RequestRejectedHandler;
import org.springframework.security.web.firewall.StrictHttpFirewall; import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcherEntry; import org.springframework.security.web.util.matcher.RequestMatcherEntry;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -235,8 +230,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
/** /**
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not * Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not
* specified, then a {@link AuthorizationManagerWebInvocationPrivilegeEvaluator} will * specified, then a {@link RequestMatcherDelegatingWebInvocationPrivilegeEvaluator}
* be created based on the list of {@link SecurityFilterChain}. * will be created based on the list of {@link SecurityFilterChain}.
* @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use * @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use
* @return the {@link WebSecurity} for further customizations * @return the {@link WebSecurity} for further customizations
*/ */
@ -305,33 +300,24 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
+ ".addSecurityFilterChainBuilder directly"); + ".addSecurityFilterChainBuilder directly");
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size(); int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize); List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
RequestMatcherDelegatingAuthorizationManager.Builder builder = RequestMatcherDelegatingAuthorizationManager List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
.builder();
boolean mappings = false;
for (RequestMatcher ignoredRequest : this.ignoredRequests) { for (RequestMatcher ignoredRequest : this.ignoredRequests) {
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead."); + ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest); SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
securityFilterChains.add(securityFilterChain); securityFilterChains.add(securityFilterChain);
builder.add(ignoredRequest, SingleResultAuthorizationManager.permitAll()); requestMatcherPrivilegeEvaluatorsEntries
mappings = true; .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
} }
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) { for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build(); SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain); securityFilterChains.add(securityFilterChain);
mappings = addAuthorizationManager(securityFilterChain, builder) || mappings; requestMatcherPrivilegeEvaluatorsEntries
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
} }
if (this.privilegeEvaluator == null) { if (this.privilegeEvaluator == null) {
AuthorizationManager<HttpServletRequest> authorizationManager = mappings ? builder.build()
: SingleResultAuthorizationManager.permitAll();
AuthorizationManagerWebInvocationPrivilegeEvaluator privilegeEvaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
authorizationManager);
privilegeEvaluator.setServletContext(this.servletContext);
if (this.privilegeEvaluatorRequestTransformer != null) {
privilegeEvaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer);
}
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator( this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
List.of(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE, List.of(privilegeEvaluator)))); requestMatcherPrivilegeEvaluatorsEntries);
} }
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) { if (this.httpFirewall != null) {
@ -364,33 +350,30 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
return result; return result;
} }
private boolean addAuthorizationManager(SecurityFilterChain securityFilterChain, private RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> getRequestMatcherPrivilegeEvaluatorsEntry(
RequestMatcherDelegatingAuthorizationManager.Builder builder) { SecurityFilterChain securityFilterChain) {
boolean mappings = false; List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = new ArrayList<>();
for (Filter filter : securityFilterChain.getFilters()) { for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor securityInterceptor) { if (filter instanceof FilterSecurityInterceptor) {
DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator( DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
securityInterceptor); (FilterSecurityInterceptor) filter);
privilegeEvaluator.setServletContext(this.servletContext); defaultWebInvocationPrivilegeEvaluator.setServletContext(this.servletContext);
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, context) -> { privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator);
HttpServletRequest request = context.getRequest();
boolean result = privilegeEvaluator.isAllowed(request.getContextPath(), request.getRequestURI(),
request.getMethod(), authentication.get());
return new AuthorizationDecision(result);
};
builder.add(securityFilterChain::matches, authorizationManager);
mappings = true;
continue; continue;
} }
if (filter instanceof AuthorizationFilter authorization) { if (filter instanceof AuthorizationFilter) {
AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager(); AuthorizationManager<HttpServletRequest> authorizationManager = ((AuthorizationFilter) filter)
builder.add(securityFilterChain::matches, .getAuthorizationManager();
(authentication, context) -> (AuthorizationDecision) authorizationManager AuthorizationManagerWebInvocationPrivilegeEvaluator evaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator(
.authorize(authentication, context.getRequest())); authorizationManager);
mappings = true; evaluator.setServletContext(this.servletContext);
if (this.privilegeEvaluatorRequestTransformer != null) {
evaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer);
}
privilegeEvaluators.add(evaluator);
} }
} }
return mappings; return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);
} }
@Override @Override

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

@ -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.
@ -34,8 +34,6 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -162,7 +160,7 @@ final class OAuth2ClientConfiguration {
* @since 6.2.0 * @since 6.2.0
*/ */
static final class OAuth2AuthorizedClientManagerRegistrar static final class OAuth2AuthorizedClientManagerRegistrar
implements ApplicationEventPublisherAware, BeanDefinitionRegistryPostProcessor, BeanFactoryAware { implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {
static final String BEAN_NAME = "authorizedClientManagerRegistrar"; static final String BEAN_NAME = "authorizedClientManagerRegistrar";
@ -181,8 +179,6 @@ final class OAuth2ClientConfiguration {
private final AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); private final AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
private ApplicationEventPublisher applicationEventPublisher;
private ListableBeanFactory beanFactory; private ListableBeanFactory beanFactory;
@Override @Override
@ -306,10 +302,6 @@ final class OAuth2ClientConfiguration {
authorizedClientProvider.setAccessTokenResponseClient(accessTokenResponseClient); authorizedClientProvider.setAccessTokenResponseClient(accessTokenResponseClient);
} }
if (this.applicationEventPublisher != null) {
authorizedClientProvider.setApplicationEventPublisher(this.applicationEventPublisher);
}
return authorizedClientProvider; return authorizedClientProvider;
} }
@ -431,11 +423,6 @@ final class OAuth2ClientConfiguration {
return objectProvider.getIfAvailable(); return objectProvider.getIfAvailable();
} }
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
} }
} }

View File

@ -78,8 +78,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer";
private BeanResolver beanResolver; private BeanResolver beanResolver;
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
@ -121,6 +119,17 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
} }
} }
/**
* Used to ensure Spring MVC request matching is cached.
*
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
* and then adds a {@link CompositeFilter} that contains
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
* FilterChainProxy under the original Bean name.
* @return
*/
@Bean @Bean
static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() { static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() { return new BeanDefinitionRegistryPostProcessor() {
@ -135,8 +144,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
} }
String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer"; String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer";
if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME)
&& !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) { if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) {
BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder
.rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class) .rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class)
@ -144,7 +151,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
.getBeanDefinition(); .getBeanDefinition();
registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer); registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer);
} }
}
BeanDefinition filterChainProxy = registry BeanDefinition filterChainProxy = registry
.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); .getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
@ -172,11 +178,7 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
/** /**
* {@link FactoryBean} to defer creation of * {@link FactoryBean} to defer creation of
* {@link HandlerMappingIntrospector#createCacheFilter()} * {@link HandlerMappingIntrospector#createCacheFilter()}
*
* @deprecated see {@link WebSecurityConfiguration} for
* {@link org.springframework.web.util.pattern.PathPattern} replacement
*/ */
@Deprecated
static class HandlerMappingIntrospectorCacheFilterFactoryBean static class HandlerMappingIntrospectorCacheFilterFactoryBean
implements ApplicationContextAware, FactoryBean<Filter> { implements ApplicationContextAware, FactoryBean<Filter> {
@ -205,11 +207,7 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
* Extends {@link FilterChainProxy} to provide as much passivity as possible but * Extends {@link FilterChainProxy} to provide as much passivity as possible but
* delegates to {@link CompositeFilter} for * delegates to {@link CompositeFilter} for
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}. * {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
*
* @deprecated see {@link WebSecurityConfiguration} for
* {@link org.springframework.web.util.pattern.PathPattern} replacement
*/ */
@Deprecated
static class CompositeFilterChainProxy extends FilterChainProxy { static class CompositeFilterChainProxy extends FilterChainProxy {
/** /**

View File

@ -16,29 +16,16 @@
package org.springframework.security.config.annotation.web.configuration; package org.springframework.security.config.annotation.web.configuration;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.DependsOn;
@ -58,18 +45,11 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor; import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
import org.springframework.security.context.DelegatingApplicationListener; import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.security.web.debug.DebugFilter;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.RequestRejectedHandler;
import org.springframework.web.filter.CompositeFilter;
import org.springframework.web.filter.ServletRequestPathFilter;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
/** /**
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web * Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
@ -206,51 +186,6 @@ public class WebSecurityConfiguration implements ImportAware {
} }
} }
/**
* Used to ensure Spring MVC request matching is cached.
*
* Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named
* HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the
* AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name
* and then adds a {@link CompositeFilter} that contains
* {@link HandlerMappingIntrospector#createCacheFilter()} and the original
* FilterChainProxy under the original Bean name.
* @return
*/
@Bean
static BeanDefinitionRegistryPostProcessor springSecurityPathPatternParserBeanDefinitionRegistryPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition filterChainProxy = registry
.getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
if (filterChainProxy.getResolvableType().isInstance(CompositeFilterChainProxy.class)) {
return;
}
BeanDefinitionBuilder pppCacheFilterBldr = BeanDefinitionBuilder
.rootBeanDefinition(ServletRequestPathFilter.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
ManagedList<BeanMetadataElement> filters = new ManagedList<>();
filters.add(pppCacheFilterBldr.getBeanDefinition());
filters.add(filterChainProxy);
BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder
.rootBeanDefinition(CompositeFilterChainProxy.class)
.addConstructorArgValue(filters);
registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
compositeSpringSecurityFilterChainBldr.getBeanDefinition());
}
};
}
/** /**
* A custom version of the Spring provided AnnotationAwareOrderComparator that uses * A custom version of the Spring provided AnnotationAwareOrderComparator that uses
* {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class * {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class
@ -284,121 +219,4 @@ public class WebSecurityConfiguration implements ImportAware {
} }
/**
* Extends {@link FilterChainProxy} to provide as much passivity as possible but
* delegates to {@link CompositeFilter} for
* {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}.
*/
static class CompositeFilterChainProxy extends FilterChainProxy {
/**
* Used for {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}
*/
private final Filter doFilterDelegate;
private final FilterChainProxy springSecurityFilterChain;
/**
* Creates a new instance
* @param filters the Filters to delegate to. One of which must be
* FilterChainProxy.
*/
CompositeFilterChainProxy(List<? extends Filter> filters) {
this.doFilterDelegate = createDoFilterDelegate(filters);
this.springSecurityFilterChain = findFilterChainProxy(filters);
}
@Override
public void afterPropertiesSet() {
this.springSecurityFilterChain.afterPropertiesSet();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
this.doFilterDelegate.doFilter(request, response, chain);
}
@Override
public List<Filter> getFilters(String url) {
return this.springSecurityFilterChain.getFilters(url);
}
@Override
public List<SecurityFilterChain> getFilterChains() {
return this.springSecurityFilterChain.getFilterChains();
}
@Override
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.springSecurityFilterChain.setSecurityContextHolderStrategy(securityContextHolderStrategy);
}
@Override
public void setFilterChainValidator(FilterChainValidator filterChainValidator) {
this.springSecurityFilterChain.setFilterChainValidator(filterChainValidator);
}
@Override
public void setFilterChainDecorator(FilterChainDecorator filterChainDecorator) {
this.springSecurityFilterChain.setFilterChainDecorator(filterChainDecorator);
}
@Override
public void setFirewall(HttpFirewall firewall) {
this.springSecurityFilterChain.setFirewall(firewall);
}
@Override
public void setRequestRejectedHandler(RequestRejectedHandler requestRejectedHandler) {
this.springSecurityFilterChain.setRequestRejectedHandler(requestRejectedHandler);
}
/**
* Used through reflection by Spring Security's Test support to lookup the
* FilterChainProxy Filters for a specific HttpServletRequest.
* @param request
* @return
*/
private List<? extends Filter> getFilters(HttpServletRequest request) {
List<SecurityFilterChain> filterChains = this.springSecurityFilterChain.getFilterChains();
for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
/**
* Creates the Filter to delegate to for doFilter
* @param filters the Filters to delegate to.
* @return the Filter for doFilter
*/
private static Filter createDoFilterDelegate(List<? extends Filter> filters) {
CompositeFilter delegate = new CompositeFilter();
delegate.setFilters(filters);
return delegate;
}
/**
* Find the FilterChainProxy in a List of Filter
* @param filters
* @return non-null FilterChainProxy
* @throws IllegalStateException if the FilterChainProxy cannot be found
*/
private static FilterChainProxy findFilterChainProxy(List<? extends Filter> filters) {
for (Filter filter : filters) {
if (filter instanceof FilterChainProxy fcp) {
return fcp;
}
if (filter instanceof DebugFilter debugFilter) {
return debugFilter.getFilterChainProxy();
}
}
throw new IllegalStateException("Couldn't find FilterChainProxy in " + filters);
}
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2025 the original author or authors. * Copyright 2002-2013 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,9 +22,7 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
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;
@ -38,14 +36,7 @@ import org.springframework.util.Assert;
* @see ChannelSecurityConfigurer * @see ChannelSecurityConfigurer
* @see UrlAuthorizationConfigurer * @see UrlAuthorizationConfigurer
* @see ExpressionUrlAuthorizationConfigurer * @see ExpressionUrlAuthorizationConfigurer
* @deprecated In modern Spring Security APIs, each API manages its own configuration
* context. As such there is no direct replacement for this interface. In the case of
* method security, please see {@link SecurityAnnotationScanner} and
* {@link AuthorizationManager}. In the case of channel security, please see
* {@code HttpsRedirectFilter}. In the case of web security, please see
* {@link AuthorizationManager}.
*/ */
@Deprecated
public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends AbstractRequestMatcherRegistry<C> { public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends AbstractRequestMatcherRegistry<C> {
private List<UrlMapping> urlMappings = new ArrayList<>(); private List<UrlMapping> urlMappings = new ArrayList<>();

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.
@ -151,7 +151,6 @@ public abstract class AbstractInterceptUrlConfigurer<C extends AbstractIntercept
return securityInterceptor; return securityInterceptor;
} }
@Deprecated
public abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T> public abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
extends AbstractConfigAttributeRequestMatcherRegistry<T> { extends AbstractConfigAttributeRequestMatcherRegistry<T> {

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() {
} }
@ -108,14 +107,15 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHt
* @return * @return
*/ */
private static CorsFilter getMvcCorsFilter(ApplicationContext context) { private static CorsFilter getMvcCorsFilter(ApplicationContext context) {
if (context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) { if (!context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
CorsConfigurationSource corsConfigurationSource = context throw new NoSuchBeanDefinitionException(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, "A Bean named "
.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, CorsConfigurationSource.class); + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + " of type "
return new CorsFilter(corsConfigurationSource); + HandlerMappingIntrospector.class.getName()
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
} }
throw new NoSuchBeanDefinitionException(CorsConfigurationSource.class, HandlerMappingIntrospector mappingIntrospector = context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
"Failed to find a bean that implements `CorsConfigurationSource`. Please ensure that you are using " HandlerMappingIntrospector.class);
+ "`@EnableWebMvc`, are publishing a `WebMvcConfigurer`, or are publishing a `CorsConfigurationSource` bean."); return new CorsFilter(mappingIntrospector);
} }
} }

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

@ -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.
@ -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)
@ -203,7 +202,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
return "hasIpAddress('" + ipAddressExpression + "')"; return "hasIpAddress('" + ipAddressExpression + "')";
} }
@Deprecated
public final class ExpressionInterceptUrlRegistry extends public final class ExpressionInterceptUrlRegistry extends
ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> { ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> {
@ -251,7 +249,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

@ -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.
@ -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() {
} }
@ -146,12 +145,12 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
* (i.e. log out) to protect against * (i.e. log out) to protect against
* <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF * <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF
* attacks</a>. If you really want to use an HTTP GET, you can use * attacks</a>. If you really want to use an HTTP GET, you can use
* <code>logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GEt, logoutUrl));</code> * <code>logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl, "GET"));</code>
* </p> * </p>
* @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

@ -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.
@ -203,7 +203,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
return authorities; return authorities;
} }
@Deprecated
public final class StandardInterceptUrlRegistry extends public final class StandardInterceptUrlRegistry extends
UrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<StandardInterceptUrlRegistry, AuthorizedUrl> { UrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<StandardInterceptUrlRegistry, AuthorizedUrl> {
@ -248,7 +247,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

@ -57,7 +57,6 @@ import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationC
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider; import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider;
import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizedClientRefreshedEventListener;
import org.springframework.security.oauth2.client.oidc.session.InMemoryOidcSessionRegistry; import org.springframework.security.oauth2.client.oidc.session.InMemoryOidcSessionRegistry;
import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation;
import org.springframework.security.oauth2.client.oidc.session.OidcSessionRegistry; import org.springframework.security.oauth2.client.oidc.session.OidcSessionRegistry;
@ -91,7 +90,6 @@ import org.springframework.security.web.authentication.LoginUrlAuthenticationEnt
import org.springframework.security.web.authentication.session.SessionAuthenticationException; import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.AndRequestMatcher;
@ -155,7 +153,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 +244,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 +268,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 +295,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 +319,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
@ -297,8 +349,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
public void init(B http) throws Exception { public void init(B http) throws Exception {
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter( OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(
this.getClientRegistrationRepository(), this.getAuthorizedClientRepository(), this.loginProcessingUrl); this.getClientRegistrationRepository(), this.getAuthorizedClientRepository(), this.loginProcessingUrl);
RequestMatcher processUri = RequestMatcherFactory.matcher(this.loginProcessingUrl);
authenticationFilter.setRequiresAuthenticationRequestMatcher(processUri);
authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.setAuthenticationFilter(authenticationFilter); this.setAuthenticationFilter(authenticationFilter);
super.loginProcessingUrl(this.loginProcessingUrl); super.loginProcessingUrl(this.loginProcessingUrl);
@ -336,24 +386,14 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService = getOidcUserService(); OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService = getOidcUserService();
OidcAuthorizationCodeAuthenticationProvider oidcAuthorizationCodeAuthenticationProvider = new OidcAuthorizationCodeAuthenticationProvider( OidcAuthorizationCodeAuthenticationProvider oidcAuthorizationCodeAuthenticationProvider = new OidcAuthorizationCodeAuthenticationProvider(
accessTokenResponseClient, oidcUserService); accessTokenResponseClient, oidcUserService);
OidcAuthorizedClientRefreshedEventListener oidcAuthorizedClientRefreshedEventListener = new OidcAuthorizedClientRefreshedEventListener();
oidcAuthorizedClientRefreshedEventListener.setUserService(oidcUserService);
oidcAuthorizedClientRefreshedEventListener
.setApplicationEventPublisher(http.getSharedObject(ApplicationContext.class));
JwtDecoderFactory<ClientRegistration> jwtDecoderFactory = this.getJwtDecoderFactoryBean(); JwtDecoderFactory<ClientRegistration> jwtDecoderFactory = this.getJwtDecoderFactoryBean();
if (jwtDecoderFactory != null) { if (jwtDecoderFactory != null) {
oidcAuthorizationCodeAuthenticationProvider.setJwtDecoderFactory(jwtDecoderFactory); oidcAuthorizationCodeAuthenticationProvider.setJwtDecoderFactory(jwtDecoderFactory);
oidcAuthorizedClientRefreshedEventListener.setJwtDecoderFactory(jwtDecoderFactory);
} }
if (userAuthoritiesMapper != null) { if (userAuthoritiesMapper != null) {
oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper);
oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper);
} }
http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider));
registerDelegateApplicationListener(this.postProcess(oidcAuthorizedClientRefreshedEventListener));
configureOidcUserRefreshedEventListener(http);
} }
else { else {
http.authenticationProvider(new OidcAuthenticationRequestChecker()); http.authenticationProvider(new OidcAuthenticationRequestChecker());
@ -380,8 +420,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
http.addFilter(this.postProcess(authorizationRequestFilter)); http.addFilter(this.postProcess(authorizationRequestFilter));
OAuth2LoginAuthenticationFilter authenticationFilter = this.getAuthenticationFilter(); OAuth2LoginAuthenticationFilter authenticationFilter = this.getAuthenticationFilter();
if (this.redirectionEndpointConfig.authorizationResponseBaseUri != null) { if (this.redirectionEndpointConfig.authorizationResponseBaseUri != null) {
authenticationFilter.setRequiresAuthenticationRequestMatcher( authenticationFilter.setFilterProcessesUrl(this.redirectionEndpointConfig.authorizationResponseBaseUri);
RequestMatcherFactory.matcher(this.redirectionEndpointConfig.authorizationResponseBaseUri));
} }
if (this.authorizationEndpointConfig.authorizationRequestRepository != null) { if (this.authorizationEndpointConfig.authorizationRequestRepository != null) {
authenticationFilter authenticationFilter
@ -582,16 +621,6 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
registerDelegateApplicationListener(listener); registerDelegateApplicationListener(listener);
} }
private void configureOidcUserRefreshedEventListener(B http) {
OidcUserRefreshedEventListener oidcUserRefreshedEventListener = new OidcUserRefreshedEventListener();
oidcUserRefreshedEventListener.setSecurityContextHolderStrategy(this.getSecurityContextHolderStrategy());
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
if (securityContextRepository != null) {
oidcUserRefreshedEventListener.setSecurityContextRepository(securityContextRepository);
}
registerDelegateApplicationListener(oidcUserRefreshedEventListener);
}
private void registerDelegateApplicationListener(ApplicationListener<?> delegate) { private void registerDelegateApplicationListener(ApplicationListener<?> delegate) {
DelegatingApplicationListener delegating = getBeanOrNull( DelegatingApplicationListener delegating = getBeanOrNull(
ResolvableType.forType(DelegatingApplicationListener.class)); ResolvableType.forType(DelegatingApplicationListener.class));
@ -668,6 +697,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 +734,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 +772,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 +837,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

@ -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.
@ -20,14 +20,13 @@ import jakarta.servlet.http.HttpServletRequest;
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 org.springframework.http.HttpMethod;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
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;
@ -46,8 +45,7 @@ final class OidcLogoutAuthenticationConverter implements AuthenticationConverter
private final ClientRegistrationRepository clientRegistrationRepository; private final ClientRegistrationRepository clientRegistrationRepository;
private RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults() private RequestMatcher requestMatcher = new AntPathRequestMatcher(DEFAULT_LOGOUT_URI, "POST");
.matcher(HttpMethod.POST, DEFAULT_LOGOUT_URI);
OidcLogoutAuthenticationConverter(ClientRegistrationRepository clientRegistrationRepository) { OidcLogoutAuthenticationConverter(ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be 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

@ -1,86 +0,0 @@
/*
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationListener;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* An {@link ApplicationListener} that listens for events of type
* {@link OidcUserRefreshedEvent} and refreshes the {@link SecurityContext}.
*
* @author Steve Riesenberg
* @since 6.5
* @see org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizedClientRefreshedEventListener
*/
final class OidcUserRefreshedEventListener implements ApplicationListener<OidcUserRefreshedEvent> {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
@Override
public void onApplicationEvent(OidcUserRefreshedEvent event) {
SecurityContext securityContext = this.securityContextHolderStrategy.createEmptyContext();
securityContext.setAuthentication(event.getAuthentication());
this.securityContextHolderStrategy.setContext(securityContext);
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (!(requestAttributes instanceof ServletRequestAttributes servletRequestAttributes)) {
return;
}
HttpServletRequest request = servletRequestAttributes.getRequest();
HttpServletResponse response = servletRequestAttributes.getResponse();
this.securityContextRepository.saveContext(securityContext, request, response);
}
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
* @param securityContextHolderStrategy the {@link SecurityContextHolderStrategy} to
* use
*/
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
/**
* Sets the {@link SecurityContextRepository} to save the {@link SecurityContext} upon
* receiving an {@link OidcUserRefreshedEvent}.
* @param securityContextRepository the {@link SecurityContextRepository} to use
*/
void setSecurityContextRepository(SecurityContextRepository securityContextRepository) {
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
this.securityContextRepository = securityContextRepository;
}
}

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