1
0
mirror of synced 2026-07-19 09:35:12 +00:00

Compare commits

..

45 Commits

Author SHA1 Message Date
github-actions[bot] ab8b139278 Release 7.1.0-M1 2026-01-19 15:23:49 +00:00
dependabot[bot] e19c34771b Bump ch.qos.logback:logback-classic from 1.5.24 to 1.5.25
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.5.24 to 1.5.25.
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.24...v_1.5.25)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-version: 1.5.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-19 10:06:16 -05:00
dependabot[bot] 318b4a785c Bump org.springframework.data:spring-data-bom from 2025.1.1 to 2025.1.2
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2025.1.1 to 2025.1.2.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/compare/2025.1.1...2025.1.2)

---
updated-dependencies:
- dependency-name: org.springframework.data:spring-data-bom
  dependency-version: 2025.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-19 10:03:41 -05:00
Robert Winch c73696f129 doclint -missing
Temporarily using -missing to allow build to pass
2026-01-16 21:55:49 -06:00
Robert Winch 35d103843b Externalize java-toolchain configuration
We should not use subprojects to perform configuration becaause it
does not allow for lazy loading and it can cause ordering problems.
In this case, the toolchain was not being used but instead it was
using the JAVA_HOME.

By splitting the configuration into a plugin and applying it to each
project it fixes the toolchain configuration
2026-01-16 16:54:00 -06:00
Robert Winch 8746ef746c Bump io.projectreactor:reactor-bom from 2025.0.1 to 2025.0.2 2026-01-16 15:19:56 -06:00
Robert Winch e72c39cabc Merge branch '7.0.x' 2026-01-16 15:19:42 -06:00
Robert Winch a8ca5b7d42 Remove 6.4.x from antora ui updates
6.4.x is no longer supported
2026-01-16 15:16:34 -06:00
Robert Winch afa5804170 Remove 6.4.x dependabot
6.4.x is no longer has OSS support
2026-01-16 15:15:37 -06:00
dependabot[bot] 15dd96bddb Bump io.spring.nullability:io.spring.nullability.gradle.plugin
Bumps [io.spring.nullability:io.spring.nullability.gradle.plugin](https://github.com/spring-gradle-plugins/nullability-plugin) from 0.0.6 to 0.0.9.
- [Release notes](https://github.com/spring-gradle-plugins/nullability-plugin/releases)
- [Commits](https://github.com/spring-gradle-plugins/nullability-plugin/compare/v0.0.6...v0.0.9)

---
updated-dependencies:
- dependency-name: io.spring.nullability:io.spring.nullability.gradle.plugin
  dependency-version: 0.0.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-16 15:10:17 -06:00
Robert Winch 6b2e0444dd Bump org.springframework:spring-framework-bom from 7.0.3-SNAPSHOT to 7.0.3
Closes gh-18515
2026-01-16 15:08:15 -06:00
Robert Winch 577d294fdc Remove milestone repository
Spring uses central for milestones now
2026-01-16 15:06:23 -06:00
Robert Winch 0993e5735e Add missing @NullMarked
Closes gh-18514
2026-01-16 14:53:16 -06:00
Robert Winch 048b6bdd88 Update to JDK 25 (release = 17)
This commit updates the build to use JDK 25 while remaining compatable with JDK 17.

Note that we must update our JAAS related tests to use release=25 due to the disabling of
the Security Manager. See
https://docs.oracle.com/en/java/javase/25/security/security-manager-is-permanently-disabled.html

Closes gh-18512
2026-01-16 11:25:59 -06:00
Robert Winch 6e9b4f86a4 Fix nullability for JDK 25
Closes gh-18511
2026-01-16 10:53:19 -06:00
Robert Winch 38b66e8407 Update to Gradle 9.2.1
Closes gh-18510
2026-01-16 10:48:28 -06:00
Robert Winch 9e5b3d9ea1 Update to Kotlin 2.3.0
Closes gh-18509
2026-01-16 10:46:58 -06:00
Robert Winch 7563932106 Update jococo 0.8.14
Closes gh-18508
2026-01-16 10:46:53 -06:00
Robert Winch 48f958cbbf Fix OAuth2AuthorizationRequestRedirectFilter constructor tests
OAuth2AuthorizationRequestRedirectFilterTests attempt to validate the constructors throw IllegalArgumentException if an invalid argument is provided, but
they are flawed because it is the relective code that is throwing the IllegalArgumentException due to imprecise type information.

This changes the tests to no longer use unnecessary reflection and casts the types so that the type information is used to target the correct
constructor.

Closes gh-18507
2026-01-16 10:34:10 -06:00
Josh Cummings 30d6b3a02b Merge branch '7.0.x' 2026-01-15 12:41:29 -07:00
Tran Ngoc Nhan cfe13c7c76 Fix typos
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-01-15 10:52:01 -07:00
Josh Cummings 3336f5f2ec Merge branch '7.0.x' 2026-01-14 14:47:31 -07:00
Josh Cummings 565896404c Merge branch '7.0.x' 2026-01-14 14:36:12 -07:00
박기현\qkrrl 91d8a04ec2 Fix duplicated use-authorization-manager in docs
Signed-off-by: 박기현\qkrrl <qkrrlgus114@naver.com>
2026-01-14 14:21:38 -07:00
Marcus Hert da Coregio 8254f589b8 Create Jackson Mixin for OneTimeTokenAuthentication
Closes gh-18095

Signed-off-by: Marcus Hert da Coregio <marcusdacoregio@gmail.com>
2026-01-14 10:35:02 -07:00
dependabot[bot] 3f773abf7c Bump io.projectreactor:reactor-bom from 2025.0.1 to 2025.0.2
Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2025.0.1 to 2025.0.2.
- [Release notes](https://github.com/reactor/reactor/releases)
- [Commits](https://github.com/reactor/reactor/compare/2025.0.1...2025.0.2)

---
updated-dependencies:
- dependency-name: io.projectreactor:reactor-bom
  dependency-version: 2025.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-14 03:05:35 +00:00
Joe Grandja 92b7c41f2f Ensure Cursor imports Spring Security
Closes gh-8492
2026-01-13 17:01:21 -05:00
Bae Jihong 8692185de1 Fix javadoc warnings for spring-security-oauth2-client
- Fix a javadoc warning
- Apply javadoc-warnings-error plugin

Closes gh-18460

Signed-off-by: Bae Jihong <dasog@naver.com>
2026-01-13 10:01:13 -06:00
Robert Winch 7ca0f7723e Fix checkstyle 2026-01-12 16:28:22 -06:00
Stefano Cordio a612522ecd Add nullability contract to PasswordEncoder#encode
Signed-off-by: Stefano Cordio <stefano.cordio@gmail.com>
2026-01-12 16:28:22 -06:00
Robert Winch fe138d6434 Merge branch '7.0.x' 2026-01-12 16:05:51 -06:00
Robert Winch 93ae52aa58 Merge branch '7.0.x' 2026-01-12 15:48:57 -06:00
Robert Winch 43fe5f6b46 Fix update-antora-ui-spring.yml 2026-01-12 14:37:34 -06:00
Robert Winch f47f81351e Merge branch '7.0.x' 2026-01-12 14:32:23 -06:00
paulvas 0d47870928 Fix: migrate compiler-warnings-error plugin to gradle
Fixes: gh-18434
Signed-off-by: paulvas <paulvas@gmail.com>
2026-01-12 13:57:57 -06:00
paulvas da4362111a Fix: Enforce compiler warnings in oauth2-core
To prevent future compiler warnings from being introduced, this change
applies the `compile-warnings-error` plugin to the
`spring-security-oauth2-core` module.

This ensures that any new warnings will fail the build, maintaining
code quality and preventing warning accumulation.

Fixes: gh-18434
Signed-off-by: Pavel Vassiliev <paulvas@gmail.com>
Signed-off-by: paulvas <paulvas@gmail.com>
2026-01-12 13:57:57 -06:00
Pavel Vassiliev 1ddccd8a39 Fix spring-security-oauth2-core compiler warnings
Closes: gh-18434
Signed-off-by: Pavel Vassiliev <paulvas@gmail.com>

Signed-off-by: paulvas <paulvas@gmail.com>
2026-01-12 13:57:57 -06:00
Robert Winch 2825aa3ff1 Merge branch '7.0.x'
Closes gh-18485
2026-01-12 13:44:13 -06:00
Robert Winch ec06f08bb6 Merge branch '7.0.x' 2026-01-12 13:38:52 -06:00
rigu1 0a6883c586 Fix Javadoc warnings in spring-security-web
* Use <code> tags for external references in DelegatingMissingAuthorityAccessDeniedHandler and SwitchUserWebFilter
* Fix typo in SessionAuthenticationException
* Apply javadoc-warnings-error plugin

Closes gh-18468

Signed-off-by: rigu1 <dlsrbtla@gmail.com>
2026-01-12 13:24:47 -06:00
rigu1 c07a2e57bd Add javadoc-warnings-error build plugin
Signed-off-by: rigu1 <dlsrbtla@gmail.com>
2026-01-12 13:24:47 -06:00
Robert Winch 5a7d93ee3b Merge branch '7.0.x'
Closes gh-18471
2026-01-09 16:55:02 -06:00
Robert Winch a3b57c470f Merge branch '7.0.x' 2026-01-09 15:25:02 -06:00
Robert Winch d1a32b4b62 Merge branch '7.0.x' 2026-01-09 15:23:29 -06:00
Robert Winch 3833650d33 Update to 7.1.0-SNAPSHOT 2026-01-09 10:32:03 -06:00
517 changed files with 6892 additions and 6772 deletions
+49 -33
View File
@@ -1,8 +1,5 @@
version: 2
registries:
spring-milestones:
type: maven-repository
url: https://repo.spring.io/milestone
shibboleth:
type: maven-repository
url: https://build.shibboleth.net/maven/releases
@@ -17,34 +14,6 @@ updates:
labels:
- 'type: dependency-upgrade'
registries:
- spring-milestones
- shibboleth
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
target-branch: 6.4.x
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
registries:
- spring-milestones
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
@@ -63,7 +32,7 @@ updates:
- version-update:semver-minor
- package-ecosystem: gradle
target-branch: main
target-branch: 7.0.x
directory: /
schedule:
interval: daily
@@ -72,7 +41,6 @@ updates:
labels:
- 'type: dependency-upgrade'
registries:
- spring-milestones
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
@@ -94,6 +62,36 @@ updates:
- version-update:semver-major
- version-update:semver-minor
- package-ecosystem: gradle
target-branch: main
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
registries:
- shibboleth
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: com.gradle.enterprise
update-types:
- version-update:semver-major
- version-update:semver-minor
- dependency-name: '*'
update-types:
- version-update:semver-major
- package-ecosystem: npm
target-branch: docs-build
directory: /
@@ -111,3 +109,21 @@ updates:
labels:
- 'type: task'
- 'in: build'
- package-ecosystem: 7.0.x
target-branch: main
directory: /docs
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
- package-ecosystem: 6.5.x
target-branch: main
directory: /docs
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
+5 -5
View File
@@ -14,15 +14,15 @@ permissions:
jobs:
snapshot-test:
name: Test Against Snapshots
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@ed473b4dafba053c63a453d2d88a89df3b3e18b3 # v1
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1
strategy:
matrix:
include:
- java-version: 17
toolchain: 17
- java-version: 25
toolchain: 25
with:
java-version: ${{ matrix.java-version }}
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.0.+ -PreactorVersion=2025.0.+ -PspringDataVersion=2025.1.+ -PmicrometerVersion=1.16.+ --stacktrace
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
secrets: inherit
send-notification:
name: Send Notification
@@ -31,6 +31,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@ed473b4dafba053c63a453d2d88a89df3b3e18b3 # v1
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
+1 -1
View File
@@ -14,4 +14,4 @@ jobs:
actions: read
contents: read
security-events: write
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@e415dadd0910c901e7a7fabd67bbb355b2324500 # 1
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@1
@@ -17,11 +17,11 @@ permissions:
jobs:
build:
name: Build
uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@v1
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 17 ]
jdk: [ 25 ]
with:
runs-on: ${{ matrix.os }}
java-version: ${{ matrix.jdk }}
@@ -29,8 +29,8 @@ jobs:
secrets: inherit
deploy-artifacts:
name: Deploy Artifacts
needs: [ build ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
needs: [ build]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1
with:
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
default-publish-milestones-central: true
@@ -38,14 +38,14 @@ jobs:
deploy-schema:
name: Deploy Schema
needs: [ build ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1
with:
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
secrets: inherit
perform-release:
name: Perform Release
needs: [ deploy-artifacts, deploy-schema ]
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1
with:
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
@@ -61,6 +61,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
-76
View File
@@ -1,76 +0,0 @@
name: Defer Issues
on:
workflow_dispatch:
permissions:
contents: read
jobs:
defer-issues:
name: Defer Issues
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
permissions:
issues: write
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Compute Version
id: compute-version
uses: spring-io/spring-release-actions/compute-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
- name: Get Today's Release Version
id: todays-release
uses: spring-io/spring-release-actions/get-todays-release-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
snapshot-version: ${{ steps.compute-version.outputs.version }}
milestone-repository: ${{ github.repository }}
milestone-token: ${{ secrets.GITHUB_TOKEN }}
- name: Compute Next Version
id: next-version
uses: spring-io/spring-release-actions/compute-next-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
version: ${{ steps.todays-release.outputs.release-version }}
- name: Schedule Next Milestone
uses: spring-io/spring-release-actions/schedule-milestone@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
version: ${{ steps.next-version.outputs.version }}
version-date: ${{ steps.next-version.outputs.version-date }}
repository: ${{ github.repository }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Move Open Issues to Next Milestone
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_MILESTONE: ${{ steps.todays-release.outputs.release-version }}
NEXT_MILESTONE: ${{ steps.next-version.outputs.version }}
run: |
current_milestone_number=$(gh api repos/${{ github.repository }}/milestones \
--jq ".[] | select(.title == \"$CURRENT_MILESTONE\") | .number")
if [ -z "$current_milestone_number" ]; then
echo "No milestone found for $CURRENT_MILESTONE"
exit 0
fi
next_milestone_number=$(gh api repos/${{ github.repository }}/milestones \
--jq ".[] | select(.title == \"$NEXT_MILESTONE\") | .number")
if [ -z "$next_milestone_number" ]; then
echo "No milestone found for $NEXT_MILESTONE"
exit 1
fi
echo "Moving open issues from milestone '$CURRENT_MILESTONE' (#$current_milestone_number) to '$NEXT_MILESTONE' (#$next_milestone_number)"
page=1
while true; do
issues=$(gh api "repos/${{ github.repository }}/issues?milestone=$current_milestone_number&state=open&per_page=100&page=$page" \
--jq '.[].number')
if [ -z "$issues" ]; then
break
fi
for issue in $issues; do
echo "Moving issue/PR #$issue to milestone $NEXT_MILESTONE"
gh api repos/${{ github.repository }}/issues/$issue \
--method PATCH \
--field milestone=$next_milestone_number \
--silent
done
page=$((page + 1))
done
echo "Done."
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
if: github.repository_owner == 'spring-projects'
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@v4
with:
ref: docs-build
fetch-depth: 1
+1 -1
View File
@@ -16,7 +16,7 @@ permissions:
jobs:
perform-release:
name: Perform Release
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@ed473b4dafba053c63a453d2d88a89df3b3e18b3 # v1
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1
with:
should-perform-release: true
project-version: ${{ inputs.version }}
@@ -19,14 +19,14 @@ jobs:
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up JDK 17
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
uses: actions/checkout@v4
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
- name: Set up Gradle
uses: gradle/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/gradle-build-action@v2
- name: Upgrade Wrappers
run: ./gradlew clean upgradeGradleWrapperAll --continue -Porg.gradle.java.installations.auto-download=false
env:
@@ -30,6 +30,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
+8 -8
View File
@@ -11,11 +11,11 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan
@@ -24,17 +24,17 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@v4
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
- name: Run Antora
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
- name: Upload Docs
id: upload
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v4
with:
name: docs
path: docs/build/site
@@ -46,6 +46,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
+2 -2
View File
@@ -11,11 +11,11 @@ jobs:
strategy:
matrix:
# List of active maintenance branches.
branch: [ main, 6.5.x, 6.4.x, 6.3.x ]
branch: [ main, 7.0.x, 6.5.x, 6.4.x, 6.3.x ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Dispatch
@@ -16,9 +16,9 @@ jobs:
name: Update on Supported Branches
strategy:
matrix:
branch: [ '6.4.x', '6.5.x', 'main' ]
branch: [ '6.5.x', '7.0.x', 'main' ]
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0
name: Update
with:
docs-branch: ${{ matrix.branch }}
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
name: Update on docs-build
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0
name: Update
with:
docs-branch: 'docs-build'
@@ -9,7 +9,7 @@ permissions:
jobs:
update-scheduled-release-version:
name: Update Scheduled Release Version
uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@v1
secrets: inherit
send-notification:
name: Send Notification
@@ -18,6 +18,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
+1 -1
View File
@@ -3,4 +3,4 @@
# See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true
java=17.0.3-tem
java=25-librca
+1 -1
View File
@@ -1,3 +1,3 @@
{
"java.import.gradle.enabled": false
"java.gradle.buildServer.enabled": "off"
}
-21
View File
@@ -68,27 +68,6 @@ The https://github.com/spring-projects/spring-security/tree/docs-build[playbook
Discover more commands with `./gradlew tasks`.
=== IDE setup (IntelliJ)
No special steps are needed to open Spring Security in IntelliJ.
=== IDE setup (Eclipse and VS Code)
To work in Eclipse or VS Code, first generate Eclipse metadata so you can import the project into Eclipse or VS Code:
[indent=0]
----
./gradlew cleanEclipse eclipse
----
If you have not built the project yet, run `./gradlew publishToMavenLocal` first so dependencies are resolved.
*VS Code:* Open the repository root as a folder. The repository includes `.vscode/settings.json` which disables automatic Gradle import so that the generated Eclipse metadata (`.classpath`, `.project`) is used. Do not use the Gradle for Java extension to import the project.
*Eclipse:* File → Import → General → Existing Projects into Workspace, then select the repository root.
The build uses a custom Eclipse plugin to work around Gradle dependency cycles that confuse IDE metadata generation. You may see Eclipse warnings about `xml-apis` from some test dependencies; those are excluded in the build and can be ignored.
== Getting Support
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
https://spring.io/support[Commercial support] is available too.
@@ -35,7 +35,6 @@ import org.springframework.security.web.FilterInvocation;
*/
@Deprecated
@NullUnmarked
@SuppressWarnings("serial")
class WebExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<FilterInvocation> {
private final Expression authorizeExpression;
+2
View File
@@ -1,5 +1,7 @@
import io.spring.gradle.IncludeRepoTask
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import trang.RncToXsd
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
buildscript {
dependencies {
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+240
View File
@@ -0,0 +1,240 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original 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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
+91
View File
@@ -0,0 +1,91 @@
@rem
@rem Copyright 2004-present the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -0,0 +1,10 @@
import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
tasks.withType(JavaCompile) {
options.compilerArgs += "-Werror"
}
tasks.withType(KotlinCompile) {
kotlinOptions.allWarningsAsErrors = true
}
@@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin<Project> {
project.tasks.check.dependsOn project.tasks.jacocoTestReport
project.jacoco {
toolVersion = '0.8.9'
toolVersion = '0.8.14'
}
}
}
@@ -5,7 +5,7 @@ def toolchainVersion() {
if (project.hasProperty('testToolchain')) {
return project.property('testToolchain').toString().toInteger()
}
return 17
return 25
}
java {
@@ -0,0 +1,7 @@
import org.gradle.api.tasks.javadoc.Javadoc
project.tasks.withType(Javadoc).configureEach {
options.addBooleanOption('Werror', true)
// temporarily disable missing to get build to pass with JDK 25
options.addStringOption('Xdoclint:all,-missing')
}
@@ -0,0 +1,30 @@
import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/**
* We need to compile with JDK 25 for nullability support, but using JDK 25 means that our tests will fail due to the
* <a href="https://docs.oracle.com/en/java/javase/25/security/security-manager-is-permanently-disabled.html">removal
* of the Java Security Manager</a>. For example, in JDK 25 {@code Subject.getSubject(AccessControlContext)} throws an
* {@code UnsupportedOperationException}.
*
* To resolve this, we must migrate tests to use the new APIs (e.g. {@code Subject.current()}) but those APIs are not
* available in the JDK 17 source, so compiling with JDK 25 and release 17 fails. The plugin overrides the test
* compilation to use release 25.
*
* @see <a href="https://docs.oracle.com/en/java/javase/25/security/security-manager-is-permanently-disabled.html">The
* Security Manager Is Permanently Disabled</a>
* @see <a href="https://inside.java/2024/07/08/quality-heads-up/">Quality Outreach Heads-up - JDK 23: Re-Specified
* Subject.getSubject API</a>
*/
tasks.withType(JavaCompile).configureEach { task ->
if (task.name == 'compileTestJava' || task.name == 'compileIntegrationTestJava') {
task.options.release.set(25)
}
}
tasks.withType(KotlinCompile).configureEach { task ->
if (task.name == 'compileTestKotlin' || task.name == 'compileIntegrationTestKotlin') {
task.kotlinOptions.jvmTarget = '25'
}
}
@@ -48,7 +48,6 @@ import org.springframework.security.jackson.SecurityJacksonModules;
* @since 7.0
* @see SecurityJacksonModules
*/
@SuppressWarnings("serial")
public class CasJacksonModule extends SecurityJacksonModule {
public CasJacksonModule() {
@@ -17,4 +17,7 @@
/**
* Jackson 3+ serialization support for CAS.
*/
@NullMarked
package org.springframework.security.cas.jackson;
import org.jspecify.annotations.NullMarked;
+1
View File
@@ -4,6 +4,7 @@ import trang.RncToXsd
apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'trang'
apply plugin: 'security-kotlin'
apply plugin: 'test-compile-target-jdk25'
configurations {
opensaml5 {
@@ -94,7 +94,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext()
.fatal("You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd",
.fatal("You cannot use any XSD older than spring-security-7.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd",
element);
}
String name = pc.getDelegate().getLocalName(element);
@@ -219,7 +219,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private boolean matchesVersionInternal(Element element) {
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-7\\.1.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
@@ -2035,9 +2035,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
*/
public HttpSecurity securityMatcher(String... patterns) {
List<RequestMatcher> matchers = new ArrayList<>();
ApplicationContext context = getSharedObject(ApplicationContext.class);
PathPatternRequestMatcher.Builder builder = context.getBeanProvider(PathPatternRequestMatcher.Builder.class)
.getIfUnique(() -> getSharedObject(PathPatternRequestMatcher.Builder.class));
PathPatternRequestMatcher.Builder builder = getSharedObject(PathPatternRequestMatcher.Builder.class);
for (String pattern : patterns) {
matchers.add(builder.matcher(pattern));
}
@@ -39,7 +39,6 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity
import org.springframework.security.web.webauthn.authentication.PublicKeyCredentialRequestOptionsFilter;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationFilter;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationProvider;
import org.springframework.security.web.webauthn.management.CredentialRecordOwnerAuthorizationManager;
import org.springframework.security.web.webauthn.management.MapPublicKeyCredentialUserEntityRepository;
import org.springframework.security.web.webauthn.management.MapUserCredentialRepository;
import org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository;
@@ -181,8 +180,6 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
webAuthnAuthnFilter = postProcess(webAuthnAuthnFilter);
WebAuthnRegistrationFilter webAuthnRegistrationFilter = new WebAuthnRegistrationFilter(userCredentials,
rpOperations);
webAuthnRegistrationFilter.setDeleteCredentialAuthorizationManager(
new CredentialRecordOwnerAuthorizationManager(userCredentials, userEntities));
PublicKeyCredentialCreationOptionsFilter creationOptionsFilter = new PublicKeyCredentialCreationOptionsFilter(
rpOperations);
if (creationOptionsRepository != null) {
@@ -16,9 +16,14 @@
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.util.Map;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -40,6 +45,7 @@ import org.springframework.security.oauth2.server.authorization.token.OAuth2Toke
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Utility methods for the OAuth 2.0 Configurers.
@@ -201,16 +207,41 @@ final class OAuth2ConfigurerUtils {
}
static <T> T getBean(HttpSecurity httpSecurity, Class<T> type) {
return httpSecurity.getSharedObject(ApplicationContext.class).getBeanProvider(type).getObject();
return httpSecurity.getSharedObject(ApplicationContext.class).getBean(type);
}
@SuppressWarnings("unchecked")
static <T> T getBean(HttpSecurity httpSecurity, ResolvableType type) {
ApplicationContext context = httpSecurity.getSharedObject(ApplicationContext.class);
String[] names = context.getBeanNamesForType(type);
if (names.length == 1) {
return (T) context.getBean(names[0]);
}
if (names.length > 1) {
throw new NoUniqueBeanDefinitionException(type, names);
}
throw new NoSuchBeanDefinitionException(type);
}
static <T> T getOptionalBean(HttpSecurity httpSecurity, Class<T> type) {
return httpSecurity.getSharedObject(ApplicationContext.class).getBeanProvider(type).getIfUnique();
Map<String, T> beansMap = BeanFactoryUtils
.beansOfTypeIncludingAncestors(httpSecurity.getSharedObject(ApplicationContext.class), type);
if (beansMap.size() > 1) {
throw new NoUniqueBeanDefinitionException(type, beansMap.size(),
"Expected single matching bean of type '" + type.getName() + "' but found " + beansMap.size() + ": "
+ StringUtils.collectionToCommaDelimitedString(beansMap.keySet()));
}
return (!beansMap.isEmpty() ? beansMap.values().iterator().next() : null);
}
@SuppressWarnings("unchecked")
static <T> T getOptionalBean(HttpSecurity httpSecurity, ResolvableType type) {
return (T) httpSecurity.getSharedObject(ApplicationContext.class).getBeanProvider(type).getIfUnique();
ApplicationContext context = httpSecurity.getSharedObject(ApplicationContext.class);
String[] names = context.getBeanNamesForType(type);
if (names.length > 1) {
throw new NoUniqueBeanDefinitionException(type, names);
}
return (names.length == 1) ? (T) context.getBean(names[0]) : null;
}
}
@@ -40,11 +40,11 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
import org.springframework.security.oauth2.server.authorization.web.OAuth2DeviceVerificationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceAuthorizationConsentAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceVerificationAuthenticationConverter;
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.DelegatingAuthenticationConverter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -279,7 +279,8 @@ public final class OAuth2DeviceVerificationEndpointConfigurer extends AbstractOA
if (StringUtils.hasText(this.consentPage)) {
deviceVerificationEndpointFilter.setConsentPage(this.consentPage);
}
builder.addFilterAfter(postProcess(deviceVerificationEndpointFilter), AuthorizationFilter.class);
builder.addFilterBefore(postProcess(deviceVerificationEndpointFilter),
AbstractPreAuthenticatedProcessingFilter.class);
}
@Override
@@ -255,9 +255,7 @@ class ServerHttpSecurityConfiguration {
if (this.passwordEncoder != null) {
manager.setPasswordEncoder(this.passwordEncoder);
}
if (this.userDetailsPasswordService != null) {
manager.setUserDetailsPasswordService(this.userDetailsPasswordService);
}
manager.setUserDetailsPasswordService(this.userDetailsPasswordService);
manager.setCompromisedPasswordChecker(this.compromisedPasswordChecker);
return this.postProcessor.postProcess(manager);
}
@@ -70,7 +70,7 @@ public final class PathPatternRequestMatcherFactoryBean
@Override
public void afterPropertiesSet() throws Exception {
if (this.basePath != null) {
this.builder = this.builder.basePath(this.basePath);
this.builder.basePath(this.basePath);
}
}
@@ -14,6 +14,8 @@
# limitations under the License.
#
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.1.xsd
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.1.xsd
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
@@ -42,7 +44,8 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.1.xsd
https\://www.springframework.org/schema/security/spring-security-7.1.xsd=org/springframework/security/config/spring-security-7.1.xsd
https\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd
@@ -12,8 +12,8 @@ base64 =
## Whether a string should be base64 encoded
attribute base64 {xsd:boolean}
request-matcher =
## Defines the strategy use for matching incoming requests. Currently the options are 'path' (for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
attribute request-matcher {"path" | "regex" | "ciRegex"}
## Defines the strategy use for matching incoming requests. Currently the options are 'mvc' (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
attribute request-matcher {"mvc" | "ant" | "regex" | "ciRegex"}
port =
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
attribute port { xsd:nonNegativeInteger }
@@ -27,14 +27,15 @@
<xs:attributeGroup name="request-matcher">
<xs:attribute name="request-matcher" use="required">
<xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
case-insensitive regular expressions.
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="path"/>
<xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/>
</xs:restriction>
@@ -1305,14 +1306,15 @@
</xs:attribute>
<xs:attribute name="request-matcher">
<xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
case-insensitive regular expressions.
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="path"/>
<xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/>
</xs:restriction>
@@ -2472,14 +2474,15 @@
<xs:attributeGroup name="filter-chain-map.attlist">
<xs:attribute name="request-matcher">
<xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
case-insensitive regular expressions.
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="path"/>
<xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/>
</xs:restriction>
@@ -2577,14 +2580,15 @@
</xs:attribute>
<xs:attribute name="request-matcher">
<xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
case-insensitive regular expressions.
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="path"/>
<xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/>
</xs:restriction>
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.security.Principal;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
@@ -86,9 +85,6 @@ import org.springframework.security.authentication.password.CompromisedPasswordE
import org.springframework.security.authorization.AuthorityAuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.FactorAuthorizationDecision;
import org.springframework.security.authorization.RequiredFactor;
import org.springframework.security.authorization.RequiredFactorError;
import org.springframework.security.authorization.event.AuthorizationEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
@@ -165,7 +161,6 @@ import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.JwtValidationException;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationServerMetadata;
import org.springframework.security.oauth2.server.authorization.OAuth2ClientRegistration;
@@ -173,22 +168,15 @@ import org.springframework.security.oauth2.server.authorization.OAuth2TokenIntro
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationException;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationConsentAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientRegistrationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceAuthorizationConsentAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceAuthorizationRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceCodeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceVerificationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2PushedAuthorizationRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenRevocationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
@@ -202,7 +190,6 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
@@ -262,7 +249,6 @@ import org.springframework.security.web.webauthn.api.AuthenticationExtensionsCli
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
import org.springframework.security.web.webauthn.api.Bytes;
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
@@ -277,7 +263,6 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestO
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
import org.springframework.security.web.webauthn.api.TestAuthenticatorAttestationResponses;
import org.springframework.security.web.webauthn.api.TestBytes;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities;
@@ -442,8 +427,6 @@ final class SerializationSamples {
generatorByClassName.put(RegisteredClient.class, (r) -> registeredClient);
generatorByClassName.put(OAuth2Authorization.class, (r) -> authorization);
generatorByClassName.put(OAuth2Authorization.Token.class, (r) -> authorization.getAccessToken());
generatorByClassName.put(OAuth2AuthorizationCode.class,
(r) -> new OAuth2AuthorizationCode("code", Instant.now(), Instant.now().plusSeconds(300)));
generatorByClassName.put(OAuth2AuthorizationConsent.class,
(r) -> OAuth2AuthorizationConsent.withId("registeredClientId", "principalName")
.scope("scope1")
@@ -469,58 +452,6 @@ final class SerializationSamples {
authenticationToken.setDetails(details);
return authenticationToken;
});
generatorByClassName.put(
org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken.class,
(r) -> {
org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken token = new org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken(
"code", principal, "https://localhost/callback", Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthorizationCodeRequestAuthenticationException.class, (r) -> {
OAuth2AuthorizationCodeRequestAuthenticationToken authToken = new OAuth2AuthorizationCodeRequestAuthenticationToken(
"https://localhost/authorize", "clientId", principal, "https://localhost/callback", "state",
authorizationRequest.getScopes(), authorizationRequest.getAdditionalParameters());
return new OAuth2AuthorizationCodeRequestAuthenticationException(
new OAuth2Error("invalid_request", "Missing required parameter", "https://example.com/error"),
authToken);
});
generatorByClassName.put(OAuth2ClientCredentialsAuthenticationToken.class, (r) -> {
OAuth2ClientCredentialsAuthenticationToken token = new OAuth2ClientCredentialsAuthenticationToken(principal,
Set.of("scope1", "scope2"), Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2DeviceCodeAuthenticationToken.class, (r) -> {
OAuth2DeviceCodeAuthenticationToken token = new OAuth2DeviceCodeAuthenticationToken("device-code",
principal, Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2RefreshTokenAuthenticationToken.class, (r) -> {
OAuth2RefreshTokenAuthenticationToken token = new OAuth2RefreshTokenAuthenticationToken("refresh-token",
principal, Set.of("scope1", "scope2"), Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2TokenExchangeAuthenticationToken.class, (r) -> {
OAuth2TokenExchangeAuthenticationToken token = new OAuth2TokenExchangeAuthenticationToken(
"urn:ietf:params:oauth:token-type:access_token", "subject-token",
"urn:ietf:params:oauth:token-type:jwt", principal, "actor-token",
"urn:ietf:params:oauth:token-type:jwt", Set.of("https://resource.example.com"), Set.of("audience"),
Set.of("scope1"), Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
OAuth2TokenExchangeActor actor = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS,
"https://issuer.example.com", OAuth2TokenClaimNames.SUB, "actor-subject"));
generatorByClassName.put(OAuth2TokenExchangeActor.class, (r) -> actor);
generatorByClassName.put(OAuth2TokenExchangeCompositeAuthenticationToken.class, (r) -> {
AbstractAuthenticationToken token = new OAuth2TokenExchangeCompositeAuthenticationToken(authentication,
List.of(actor));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthorizationConsentAuthenticationToken.class, (r) -> {
OAuth2AuthorizationConsentAuthenticationToken authenticationToken = new OAuth2AuthorizationConsentAuthenticationToken(
"authorizationUri", "clientId", principal, "state", authorizationRequest.getScopes(),
@@ -737,12 +668,6 @@ final class SerializationSamples {
generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true));
generatorByClassName.put(AuthorityAuthorizationDecision.class,
(r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER")));
RequiredFactor factor = RequiredFactor.withAuthority("authority").validDuration(Duration.ofSeconds(5)).build();
generatorByClassName.put(RequiredFactor.class, (r) -> factor);
RequiredFactorError error = RequiredFactorError.createMissing(factor);
generatorByClassName.put(RequiredFactorError.class, (r) -> error);
generatorByClassName.put(FactorAuthorizationDecision.class,
(r) -> new FactorAuthorizationDecision(List.of(error)));
generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException());
generatorByClassName.put(AuthorizationEvent.class,
(r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source",
@@ -933,8 +858,6 @@ final class SerializationSamples {
generatorByClassName.put(CredentialPropertiesOutput.class, (o) -> credentialOutput);
generatorByClassName.put(ImmutableAuthenticationExtensionsClientOutputs.class, (o) -> outputs);
generatorByClassName.put(AuthenticatorAssertionResponse.class, (r) -> response);
generatorByClassName.put(AuthenticatorAttestationResponse.class,
(r) -> TestAuthenticatorAttestationResponses.createAuthenticatorAttestationResponse().build());
generatorByClassName.put(RelyingPartyAuthenticationRequest.class, (r) -> authRequest);
generatorByClassName.put(PublicKeyCredential.class, (r) -> credential);
generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken);
@@ -33,10 +33,10 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.apache.commons.lang3.ObjectUtils;
@@ -207,7 +207,10 @@ class SpringSecurityCoreVersionSerializableTests {
boolean hasSerialVersion = Stream.of(clazz.getDeclaredFields())
.map(Field::getName)
.anyMatch((n) -> n.equals("serialVersionUID"));
if (!hasSerialVersion && !hasSuppressSerialInSource(clazz)) {
SuppressWarnings suppressWarnings = clazz.getAnnotation(SuppressWarnings.class);
boolean hasSerialIgnore = suppressWarnings == null
|| Arrays.asList(suppressWarnings.value()).contains("Serial");
if (!hasSerialVersion && !hasSerialIgnore) {
classes.add(clazz);
continue;
}
@@ -246,62 +249,11 @@ class SpringSecurityCoreVersionSerializableTests {
return classes.stream();
}
private static boolean hasSuppressSerialInSource(Class<?> clazz) {
try {
Class<?> fileClass = clazz;
while (fileClass.getEnclosingClass() != null) {
fileClass = fileClass.getEnclosingClass();
}
var codeSource = fileClass.getProtectionDomain().getCodeSource();
if (codeSource == null) {
return false;
}
Path sourceFile = findSourceFile(Path.of(codeSource.getLocation().toURI()), fileClass);
if (sourceFile == null) {
return false;
}
return hasSuppressSerialAnnotation(Files.readAllLines(sourceFile), clazz.getSimpleName());
}
catch (Exception ex) {
return false;
}
}
private static Path findSourceFile(Path start, Class<?> clazz) {
String relativePath = clazz.getName().replace('.', '/') + ".java";
Path dir = start;
for (int i = 0; i < 10 && dir != null; i++) {
for (String sourceRoot : List.of("src/main/java", "src/test/java")) {
Path candidate = dir.resolve(sourceRoot).resolve(relativePath);
if (Files.exists(candidate)) {
return candidate;
}
}
dir = dir.getParent();
}
return null;
}
private static boolean hasSuppressSerialAnnotation(List<String> lines, String simpleClassName) {
Pattern classDeclaration = Pattern
.compile("\\b(?:class|interface|enum|record)\\s+" + Pattern.quote(simpleClassName) + "\\b");
for (int i = 0; i < lines.size(); i++) {
if (classDeclaration.matcher(lines.get(i)).find()) {
for (int j = Math.max(0, i - 5); j < i; j++) {
String line = lines.get(j);
if (line.contains("@SuppressWarnings") && line.contains("\"serial\"")) {
return true;
}
}
}
}
return false;
}
private static String getCurrentVersion() {
String version = System.getProperty("springSecurityVersion");
String[] parts = version.split("\\.");
return parts[0] + "." + parts[1] + ".x";
parts[2] = "x";
return String.join(".", parts);
}
private static String getPreviousVersion() {
@@ -314,7 +266,8 @@ class SpringSecurityCoreVersionSerializableTests {
parts[0] = String.valueOf(Integer.parseInt(parts[0]) - 1);
parts[1] = "5"; // FIXME: this should not be hard coded
}
return parts[0] + "." + parts[1] + ".x";
parts[2] = "x";
return String.join(".", parts);
}
}
@@ -114,7 +114,7 @@ public class SecurityNamespaceHandlerTests {
"<user-service id='us'><user name='bob' password='bobspassword' authorities='ROLE_A' /></user-service>",
"3.0.3", null))
.withMessageContaining(
"You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd");
"You cannot use any XSD older than spring-security-7.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd");
}
// SEC-1868
@@ -37,7 +37,6 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@@ -111,21 +110,6 @@ public class WebSecurityTests {
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST);
}
// gh-19128
@Test
public void ignoringWhenBuilderBeanWithBasePathThenHonorsBasePath() throws Exception {
loadConfig(IgnoringBuilderBeanConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
@@ -217,52 +201,6 @@ public class WebSecurityTests {
}
// gh-19128
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class IgnoringBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/path");
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.httpBasic(withDefaults())
.authorizeHttpRequests((requests) -> requests
.anyRequest().denyAll());
// @formatter:on
return http.build();
}
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(PasswordEncodedUser.user());
}
@RestController
static class PathController {
@RequestMapping("/path")
String path() {
return "path";
}
}
}
@Configuration
@EnableWebSecurity
static class RequestRejectedHandlerConfig {
@@ -452,18 +452,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
this.mvc.perform(requestWithAdmin).andExpect(status().isOk());
}
@Test
public void requestMatchersWhenBuilderBeanWithBasePathAndRawStringThenHonorsBasePath() throws Exception {
this.spring.register(RequestMatchersRawStringServletPathConfig.class, BasicController.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder matchedByBasePath = get("/spring/path")
.servletPath("/spring")
.with(user("user").roles("USER"));
// @formatter:on
this.mvc.perform(matchedByBasePath).andExpect(status().isForbidden());
this.mvc.perform(get("/path").with(user("user").roles("USER"))).andExpect(status().isOk());
}
@Test
public void getWhenAnyRequestAuthenticatedConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception {
this.spring.register(AuthenticatedConfig.class, BasicController.class).autowire();
@@ -1371,32 +1359,6 @@ public class AuthorizeHttpRequestsConfigurerTests {
}
@Configuration
@EnableWebMvc
@EnableWebSecurity
static class RequestMatchersRawStringServletPathConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/path").hasRole("ADMIN")
.anyRequest().permitAll()
)
.build();
// @formatter:on
}
}
@Configuration
@EnableWebSecurity
static class AuthenticatedConfig {
@@ -40,7 +40,6 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.users.AuthenticationTestConfiguration;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.authority.FactorGrantedAuthority;
import org.springframework.security.core.context.SecurityContextChangedListener;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -154,17 +153,6 @@ public class FormLoginConfigurerTests {
// @formatter:on
}
// gh-19128
@Test
public void loginWhenBuilderBeanWithBasePathThenLoginProcessingUrlIgnoresBasePath() throws Exception {
this.spring.register(FormLoginBuilderBeanConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
@@ -531,37 +519,6 @@ public class FormLoginConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
@EnableWebMvc
static class FormLoginBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((requests) -> requests
.anyRequest().authenticated())
.formLogin(withDefaults());
// @formatter:on
return http.build();
}
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(PasswordEncodedUser.user());
}
}
@Configuration
@EnableWebSecurity
static class FormLoginInLambdaConfig {
@@ -125,34 +125,6 @@ public class HttpSecuritySecurityMatchersTests {
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@Test
public void securityMatcherWhenBuilderBeanWithBasePathThenHonorsBasePath() throws Exception {
loadConfig(SecurityMatcherBuilderBeanConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@Test
public void securityMatchersWhenBuilderBeanWithBasePathAndRawStringsThenHonorsBasePath() throws Exception {
loadConfig(SecurityMatchersBuilderBeanConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@Test
public void securityMatchersWhenMultiMvcMatcherInLambdaThenAllPathsAreDenied() throws Exception {
loadConfig(MultiMvcMatcherInLambdaConfig.class);
@@ -458,83 +430,6 @@ public class HttpSecuritySecurityMatchersTests {
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
@Import(UsersConfig.class)
static class SecurityMatcherBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatcher("/path")
.httpBasic(withDefaults())
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().denyAll());
// @formatter:on
return http.build();
}
@RestController
static class PathController {
@RequestMapping("/path")
String path() {
return "path";
}
}
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
@Import(UsersConfig.class)
static class SecurityMatchersBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
// @formatter:off
http
.securityMatchers((matchers) -> matchers
.requestMatchers("/path")
)
.httpBasic(withDefaults())
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().denyAll()
);
// @formatter:on
return http.build();
}
@RestController
static class PathController {
@RequestMapping("/path")
String path() {
return "path";
}
}
}
@Configuration
static class UsersConfig {
@@ -35,7 +35,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -128,17 +127,6 @@ public class LogoutConfigurerTests {
// @formatter:on
}
// gh-19128
@Test
public void logoutWhenBuilderBeanWithBasePathThenLogoutUrlIgnoresBasePath() throws Exception {
this.spring.register(LogoutBuilderBeanConfig.class).autowire();
// @formatter:off
this.mvc.perform(post("/logout").with(csrf()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// SEC-2311
@Test
public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
@@ -536,29 +524,6 @@ public class LogoutConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
static class LogoutBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.logout(withDefaults());
// @formatter:on
return http.build();
}
}
@Configuration
@EnableWebSecurity
static class CsrfDisabledConfig {
@@ -26,7 +26,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.test.web.servlet.MockMvc;
@@ -67,16 +66,6 @@ public class PasswordManagementConfigurerTests {
.andExpect(redirectedUrl("/custom-change-password-page"));
}
// gh-19128
@Test
public void changePasswordWhenBuilderBeanWithBasePathThenChangePasswordUrlIgnoresBasePath() throws Exception {
this.spring.register(PasswordManagementBuilderBeanConfig.class).autowire();
this.mvc.perform(get("/.well-known/change-password"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/change-password"));
}
@Test
public void whenSettingNullChangePasswordPage() {
PasswordManagementConfigurer configurer = new PasswordManagementConfigurer();
@@ -113,29 +102,6 @@ public class PasswordManagementConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
static class PasswordManagementBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http
.passwordManagement(withDefaults())
.build();
// @formatter:on
}
}
@Configuration
@EnableWebSecurity
static class PasswordManagementWithCustomChangePasswordPageConfig {
@@ -34,7 +34,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
@@ -186,21 +185,6 @@ public class RequestCacheConfigurerTests {
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
// gh-19128
@Test
public void getWhenBuilderBeanWithBasePathThenSavedRequestMatcherIgnoresBasePath() throws Exception {
this.spring.register(RequestCacheBuilderBeanConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(RequestCacheResultMatcher.redirectToCachedRequest());
}
@Test
public void getWhenBookmarkedRequestIsAllMediaTypeThenPostAuthenticationRemembers() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
@@ -417,31 +401,6 @@ public class RequestCacheConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
static class RequestCacheBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((requests) -> requests
.anyRequest().authenticated())
.formLogin(withDefaults());
// @formatter:on
return http.build();
}
}
@Configuration
@EnableWebSecurity
static class RequestCacheDisabledConfig {
@@ -43,16 +43,9 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.ui.DefaultResourcesFilter;
import org.springframework.security.web.webauthn.api.Bytes;
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.api.TestCredentialRecords;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationFilter;
import org.springframework.security.web.webauthn.management.MapPublicKeyCredentialUserEntityRepository;
import org.springframework.security.web.webauthn.management.MapUserCredentialRepository;
import org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository;
import org.springframework.security.web.webauthn.management.UserCredentialRepository;
import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
import org.springframework.security.web.webauthn.registration.HttpSessionPublicKeyCredentialCreationOptionsRepository;
import org.springframework.test.web.servlet.MockMvc;
@@ -65,7 +58,6 @@ import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.Mockito.mock;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@@ -265,24 +257,6 @@ public class WebAuthnConfigurerTests {
.andExpect(content().string(expectedBody));
}
@Test
void webauthnWhenDeleteAndCredentialBelongsToUserThenNoContent() throws Exception {
this.spring.register(DeleteCredentialConfiguration.class).autowire();
this.mvc
.perform(delete("/webauthn/register/" + DeleteCredentialConfiguration.CREDENTIAL_ID_BASE64URL)
.with(authentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"))))
.andExpect(status().isNoContent());
}
@Test
void webauthnWhenDeleteAndCredentialBelongsToDifferentUserThenForbidden() throws Exception {
this.spring.register(DeleteCredentialConfiguration.class).autowire();
this.mvc
.perform(delete("/webauthn/register/" + DeleteCredentialConfiguration.CREDENTIAL_ID_BASE64URL)
.with(authentication(new TestingAuthenticationToken("other-user", "password", "ROLE_USER"))))
.andExpect(status().isForbidden());
}
@Configuration
@EnableWebSecurity
static class ConfigCredentialCreationOptionsRepository {
@@ -501,47 +475,4 @@ public class WebAuthnConfigurerTests {
}
@Configuration
@EnableWebSecurity
static class DeleteCredentialConfiguration {
static final String CREDENTIAL_ID_BASE64URL = "NauGCN7bZ5jEBwThcde51g";
static final Bytes USER_ENTITY_ID = Bytes.fromBase64("vKBFhsWT3gQnn-gHdT4VXIvjDkVXVYg5w8CLGHPunMM");
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager();
}
@Bean
WebAuthnRelyingPartyOperations webAuthnRelyingPartyOperations() {
return mock(WebAuthnRelyingPartyOperations.class);
}
@Bean
UserCredentialRepository userCredentialRepository() {
MapUserCredentialRepository repository = new MapUserCredentialRepository();
repository.save(TestCredentialRecords.userCredential().build());
return repository;
}
@Bean
PublicKeyCredentialUserEntityRepository userEntityRepository() {
MapPublicKeyCredentialUserEntityRepository repository = new MapPublicKeyCredentialUserEntityRepository();
repository.save(ImmutablePublicKeyCredentialUserEntity.builder()
.name("user")
.id(USER_ENTITY_ID)
.displayName("User")
.build());
return repository;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.csrf(AbstractHttpConfigurer::disable).webAuthn(Customizer.withDefaults()).build();
}
}
}
@@ -56,7 +56,6 @@ import org.springframework.security.config.annotation.web.configurers.oauth2.cli
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
@@ -441,18 +440,6 @@ public class OAuth2LoginConfigurerTests {
then(redirectStrategy).should().sendRedirect(any(), any(), anyString());
}
// gh-19128
@Test
public void oauth2LoginWhenBuilderBeanWithBasePathThenLoginProcessingUrlIgnoresBasePath() throws Exception {
loadConfig(OAuth2LoginBuilderBeanConfig.class);
String requestUri = "/login/oauth2/code/google";
this.request = get(requestUri).build();
this.request.setParameter("code", "code123");
this.request.setParameter("state", "state123");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
assertThat(this.response.getRedirectedUrl()).endsWith("/login?error");
}
// gh-5347
@Test
public void oauth2LoginWithOneClientConfiguredThenRedirectForAuthorization() throws Exception {
@@ -801,31 +788,6 @@ public class OAuth2LoginConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
static class OAuth2LoginBuilderBeanConfig extends CommonSecurityFilterChainConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.oauth2Login((login) -> login
.clientRegistrationRepository(
new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)));
// @formatter:on
return super.configureFilterChain(http);
}
}
@Configuration
@EnableWebSecurity
static class OAuth2LoginConfigFormLogin extends CommonSecurityFilterChainConfig {
@@ -45,7 +45,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -159,8 +158,6 @@ public class OAuth2ClientCredentialsGrantTests {
private static AuthenticationFailureHandler authenticationFailureHandler;
private static PasswordEncoder passwordEncoder;
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
@@ -186,9 +183,6 @@ public class OAuth2ClientCredentialsGrantTests {
authenticationProvidersConsumer = mock(Consumer.class);
authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class);
authenticationFailureHandler = mock(AuthenticationFailureHandler.class);
passwordEncoder = mock(PasswordEncoder.class);
given(passwordEncoder.matches(any(), any())).willReturn(true);
given(passwordEncoder.upgradeEncoding(any())).willReturn(false);
db = new EmbeddedDatabaseBuilder().generateUniqueName(true)
.setType(EmbeddedDatabaseType.HSQL)
.setScriptEncoding("UTF-8")
@@ -502,26 +496,6 @@ public class OAuth2ClientCredentialsGrantTests {
.andExpect(jsonPath("$.token_type").value(OAuth2AccessToken.TokenType.DPOP.getValue()));
}
@Test
public void requestWhenTokenRequestWithMultiplePasswordEncodersThenPrimaryPasswordEncoderUsed() throws Exception {
this.spring.register(AuthorizationServerConfigurationWithMultiplePasswordEncoders.class).autowire();
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
this.registeredClientRepository.save(registeredClient);
this.mvc
.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
.header(HttpHeaders.AUTHORIZATION,
"Basic " + encodeBasicAuth(registeredClient.getClientId(), registeredClient.getClientSecret())))
.andExpect(status().isOk())
.andExpect(jsonPath("$.access_token").isNotEmpty())
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
verify(passwordEncoder).matches(any(), any());
}
private static String generateDPoPProof(String tokenEndpointUri) {
// @formatter:off
Map<String, Object> publicJwk = TestJwks.DEFAULT_EC_JWK
@@ -684,16 +658,4 @@ public class OAuth2ClientCredentialsGrantTests {
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class AuthorizationServerConfigurationWithMultiplePasswordEncoders extends AuthorizationServerConfiguration {
@Primary
@Bean
PasswordEncoder primaryPasswordEncoder() {
return passwordEncoder;
}
}
}
@@ -79,7 +79,6 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
import org.springframework.security.oauth2.server.authorization.OAuth2ClientRegistration;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientRegistrationAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientRegistrationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientRegistrationAuthenticationValidator;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository.RegisteredClientParametersMapper;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
@@ -412,102 +411,6 @@ public class OAuth2ClientRegistrationTests {
.isCloseTo(expectedSecretExpiryDate, allowedDelta);
}
@Test
public void requestWhenProtocolRelativeRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["//client.example.com/path"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenJavascriptSchemeRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["javascript:alert(document.cookie)"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenDataSchemeRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["data:text/html,<h1>content</h1>"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenHttpJwkSetUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["https://client.example.com"],
"grant_types": ["authorization_code"],
"jwks_uri": "http://169.254.169.254/keys",
"token_endpoint_auth_method": "private_key_jwt"
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenArbitraryScopeThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["https://client.example.com"],
"grant_types": ["client_credentials"],
"scope": "read write"
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
private int requestWhenInvalidClientMetadataThenBadRequest(String json) throws Exception {
String clientRegistrationScope = "client.create";
// @formatter:off
RegisteredClient clientRegistrar = RegisteredClient.withId("client-registrar-" + System.nanoTime())
.clientId("client-registrar-" + System.nanoTime())
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope(clientRegistrationScope)
.build();
// @formatter:on
this.registeredClientRepository.save(clientRegistrar);
MvcResult tokenResult = this.mvc
.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
.with(httpBasic(clientRegistrar.getClientId(), "secret")))
.andExpect(status().isOk())
.andReturn();
OAuth2AccessToken accessToken = readAccessTokenResponse(tokenResult.getResponse()).getAccessToken();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setBearerAuth(accessToken.getTokenValue());
MvcResult registerResult = this.mvc
.perform(post(ISSUER.concat(DEFAULT_OAUTH2_CLIENT_REGISTRATION_ENDPOINT_URI)).headers(httpHeaders)
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andReturn();
return registerResult.getResponse().getStatus();
}
private OAuth2ClientRegistration registerClient(OAuth2ClientRegistration clientRegistration) throws Exception {
// ***** (1) Obtain the "initial" access token used for registering the client
@@ -593,17 +496,6 @@ public class OAuth2ClientRegistrationTests {
return clientRegistrationHttpMessageConverter.read(OAuth2ClientRegistration.class, httpResponse);
}
private static Consumer<List<AuthenticationProvider>> scopePermissiveValidatorCustomizer() {
return (authenticationProviders) -> authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof OAuth2ClientRegistrationAuthenticationProvider provider) {
provider.setAuthenticationValidator(
OAuth2ClientRegistrationAuthenticationValidator.DEFAULT_REDIRECT_URI_VALIDATOR
.andThen(OAuth2ClientRegistrationAuthenticationValidator.DEFAULT_JWK_SET_URI_VALIDATOR)
.andThen(OAuth2ClientRegistrationAuthenticationValidator.SIMPLE_SCOPE_VALIDATOR));
}
});
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class CustomClientRegistrationConfiguration extends AuthorizationServerConfiguration {
@@ -620,7 +512,7 @@ public class OAuth2ClientRegistrationTests {
.clientRegistrationRequestConverter(authenticationConverter)
.clientRegistrationRequestConverters(authenticationConvertersConsumer)
.authenticationProvider(authenticationProvider)
.authenticationProviders(scopePermissiveValidatorCustomizer().andThen(authenticationProvidersConsumer))
.authenticationProviders(authenticationProvidersConsumer)
.clientRegistrationResponseHandler(authenticationSuccessHandler)
.errorResponseHandler(authenticationFailureHandler)
)
@@ -647,7 +539,7 @@ public class OAuth2ClientRegistrationTests {
authorizationServer
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(scopePermissiveValidatorCustomizer().andThen(configureClientRegistrationConverters()))
.authenticationProviders(configureClientRegistrationConverters())
)
)
.authorizeHttpRequests((authorize) ->
@@ -685,7 +577,7 @@ public class OAuth2ClientRegistrationTests {
authorizationServer
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(scopePermissiveValidatorCustomizer().andThen(configureClientRegistrationConverters()))
.authenticationProviders(configureClientRegistrationConverters())
)
)
.authorizeHttpRequests((authorize) ->
@@ -722,7 +614,6 @@ public class OAuth2ClientRegistrationTests {
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.openRegistrationAllowed(true)
.authenticationProviders(scopePermissiveValidatorCustomizer())
)
)
.authorizeHttpRequests((authorize) ->
@@ -736,30 +627,6 @@ public class OAuth2ClientRegistrationTests {
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class DefaultValidatorConfiguration extends AuthorizationServerConfiguration {
// Override with Customizer.withDefaults() so the default (strict)
// OAuth2ClientRegistrationAuthenticationValidator is in effect.
// @formatter:off
@Bean
@Override
SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.oauth2AuthorizationServer((authorizationServer) ->
authorizationServer
.clientRegistrationEndpoint(Customizer.withDefaults())
)
.authorizeHttpRequests((authorize) ->
authorize.anyRequest().authenticated()
);
return http.build();
}
// @formatter:on
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class AuthorizationServerConfiguration {
@@ -770,10 +637,7 @@ public class OAuth2ClientRegistrationTests {
http
.oauth2AuthorizationServer((authorizationServer) ->
authorizationServer
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(scopePermissiveValidatorCustomizer())
)
.clientRegistrationEndpoint(Customizer.withDefaults())
)
.authorizeHttpRequests((authorize) ->
authorize.anyRequest().authenticated()
@@ -359,7 +359,7 @@ public class OAuth2DeviceCodeGrantTests {
}
@Test
public void requestWhenDeviceAuthorizationConsentRequestUnauthenticatedThenUnauthorized() throws Exception {
public void requestWhenDeviceAuthorizationConsentRequestUnauthenticatedThenBadRequest() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
// @formatter:off
@@ -392,7 +392,7 @@ public class OAuth2DeviceCodeGrantTests {
// @formatter:off
this.mvc.perform(post(DEFAULT_DEVICE_VERIFICATION_ENDPOINT_URI)
.params(parameters))
.andExpect(status().isUnauthorized());
.andExpect(status().isBadRequest());
// @formatter:on
}
@@ -97,7 +97,6 @@ import org.springframework.security.oauth2.server.authorization.oidc.OidcClientR
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientConfigurationAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientRegistrationAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientRegistrationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientRegistrationAuthenticationValidator;
import org.springframework.security.oauth2.server.authorization.oidc.converter.OidcClientRegistrationRegisteredClientConverter;
import org.springframework.security.oauth2.server.authorization.oidc.converter.RegisteredClientOidcClientRegistrationConverter;
import org.springframework.security.oauth2.server.authorization.oidc.http.converter.OidcClientRegistrationHttpMessageConverter;
@@ -546,129 +545,6 @@ public class OidcClientRegistrationTests {
.isCloseTo(expectedSecretExpiryDate, allowedDelta);
}
@Test
public void requestWhenProtocolRelativeRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["//client.example.com/path"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenJavascriptSchemeRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["javascript:alert(document.cookie)"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenDataSchemeRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["data:text/html,<h1>content</h1>"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenJavascriptSchemePostLogoutRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["https://client.example.com"],
"post_logout_redirect_uris": ["javascript:alert(document.cookie)"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenDataSchemePostLogoutRedirectUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["https://client.example.com"],
"post_logout_redirect_uris": ["data:text/html,<h1>content</h1>"],
"grant_types": ["authorization_code"]
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenHttpJwkSetUriThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["https://client.example.com"],
"grant_types": ["authorization_code"],
"jwks_uri": "http://169.254.169.254/keys",
"token_endpoint_auth_method": "private_key_jwt"
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
@Test
public void requestWhenArbitraryScopeThenBadRequest() throws Exception {
this.spring.register(DefaultValidatorConfiguration.class).autowire();
assertThat(requestWhenInvalidClientMetadataThenBadRequest("""
{
"client_name": "client-name",
"redirect_uris": ["https://client.example.com"],
"grant_types": ["authorization_code"],
"scope": "read write"
}
""")).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
private int requestWhenInvalidClientMetadataThenBadRequest(String json) throws Exception {
String clientRegistrationScope = "client.create";
String clientId = "client-registrar-" + System.nanoTime();
// @formatter:off
RegisteredClient clientRegistrar = RegisteredClient.withId(clientId)
.clientId(clientId)
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope(clientRegistrationScope)
.build();
// @formatter:on
this.registeredClientRepository.save(clientRegistrar);
MvcResult tokenResult = this.mvc
.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
.with(httpBasic(clientId, "secret")))
.andExpect(status().isOk())
.andReturn();
OAuth2AccessToken accessToken = readAccessTokenResponse(tokenResult.getResponse()).getAccessToken();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setBearerAuth(accessToken.getTokenValue());
MvcResult registerResult = this.mvc
.perform(post(ISSUER.concat(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)).headers(httpHeaders)
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andReturn();
return registerResult.getResponse().getStatus();
}
private OidcClientRegistration registerClient(OidcClientRegistration clientRegistration) throws Exception {
// ***** (1) Obtain the "initial" access token used for registering the client
@@ -766,18 +642,6 @@ public class OidcClientRegistrationTests {
return clientRegistrationHttpMessageConverter.read(OidcClientRegistration.class, httpResponse);
}
private static Consumer<List<AuthenticationProvider>> scopePermissiveValidatorCustomizer() {
return (authenticationProviders) -> authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof OidcClientRegistrationAuthenticationProvider provider) {
provider.setAuthenticationValidator(
OidcClientRegistrationAuthenticationValidator.DEFAULT_REDIRECT_URI_VALIDATOR.andThen(
OidcClientRegistrationAuthenticationValidator.DEFAULT_POST_LOGOUT_REDIRECT_URI_VALIDATOR)
.andThen(OidcClientRegistrationAuthenticationValidator.DEFAULT_JWK_SET_URI_VALIDATOR)
.andThen(OidcClientRegistrationAuthenticationValidator.SIMPLE_SCOPE_VALIDATOR));
}
});
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class CustomClientRegistrationConfiguration extends AuthorizationServerConfiguration {
@@ -796,7 +660,7 @@ public class OidcClientRegistrationTests {
.clientRegistrationRequestConverter(authenticationConverter)
.clientRegistrationRequestConverters(authenticationConvertersConsumer)
.authenticationProvider(authenticationProvider)
.authenticationProviders(scopePermissiveValidatorCustomizer().andThen(authenticationProvidersConsumer))
.authenticationProviders(authenticationProvidersConsumer)
.clientRegistrationResponseHandler(authenticationSuccessHandler)
.errorResponseHandler(authenticationFailureHandler)
)
@@ -826,7 +690,7 @@ public class OidcClientRegistrationTests {
oidc
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(scopePermissiveValidatorCustomizer().andThen(configureClientRegistrationConverters()))
.authenticationProviders(configureClientRegistrationConverters())
)
)
)
@@ -867,7 +731,7 @@ public class OidcClientRegistrationTests {
oidc
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(scopePermissiveValidatorCustomizer().andThen(configureClientRegistrationConverters()))
.authenticationProviders(configureClientRegistrationConverters())
)
)
)
@@ -891,33 +755,6 @@ public class OidcClientRegistrationTests {
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class DefaultValidatorConfiguration extends AuthorizationServerConfiguration {
// Override with Customizer.withDefaults() so the default (strict)
// OidcClientRegistrationAuthenticationValidator is in effect.
// @formatter:off
@Bean
@Override
SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.oauth2AuthorizationServer((authorizationServer) ->
authorizationServer
.oidc((oidc) ->
oidc
.clientRegistrationEndpoint(Customizer.withDefaults())
)
)
.authorizeHttpRequests((authorize) ->
authorize.anyRequest().authenticated()
);
return http.build();
}
// @formatter:on
}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class AuthorizationServerConfiguration {
@@ -930,10 +767,7 @@ public class OidcClientRegistrationTests {
authorizationServer
.oidc((oidc) ->
oidc
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(scopePermissiveValidatorCustomizer())
)
.clientRegistrationEndpoint(Customizer.withDefaults())
)
)
.authorizeHttpRequests((authorize) ->
@@ -60,7 +60,6 @@ import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.FactorGrantedAuthority;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@@ -211,8 +210,7 @@ public class OidcTests {
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user").roles("A", "B")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user").roles("A", "B")))
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -272,8 +270,7 @@ public class OidcTests {
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user").roles("A", "B")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user").roles("A", "B")))
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -338,8 +335,7 @@ public class OidcTests {
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI)).queryParams(authorizationRequestParameters)
.with(user("user")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
@@ -392,8 +388,7 @@ public class OidcTests {
registeredClient1);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user1")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user1")))
.andExpect(status().is3xxRedirection())
.andReturn();
@@ -429,8 +424,7 @@ public class OidcTests {
authorizationRequestParameters = getAuthorizationRequestParameters(registeredClient2);
mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user2")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user2")))
.andExpect(status().is3xxRedirection())
.andReturn();
@@ -503,8 +497,7 @@ public class OidcTests {
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -544,8 +537,7 @@ public class OidcTests {
registeredClient);
MvcResult mvcResult = this.mvc
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
.with(user("user")
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
.with(user("user")))
.andExpect(status().is3xxRedirection())
.andReturn();
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -40,7 +40,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@@ -99,19 +98,6 @@ public class OneTimeTokenLoginConfigurerTests {
.andExpectAll(status().isFound(), redirectedUrl("/"), authenticated());
}
// gh-19128
@Test
void oneTimeTokenWhenBuilderBeanWithBasePathThenGenerateAndLoginUrlsIgnoreBasePath() throws Exception {
this.spring.register(OneTimeTokenBuilderBeanConfig.class).autowire();
this.mvc.perform(post("/ott/generate").param("username", "user").with(csrf()))
.andExpectAll(status().isFound(), redirectedUrl("/login/ott"));
String token = getLastToken().getTokenValue();
this.mvc.perform(post("/login/ott").param("token", token).with(csrf()))
.andExpectAll(status().isFound(), redirectedUrl("/"), authenticated());
}
@Test
void oneTimeTokenWhenDifferentAuthenticationUrlsThenCanAuthenticate() throws Exception {
this.spring.register(OneTimeTokenDifferentUrlsConfig.class).autowire();
@@ -310,41 +296,6 @@ public class OneTimeTokenLoginConfigurerTests {
}
// gh-19128
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@Import(UserDetailsServiceConfig.class)
static class OneTimeTokenBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http,
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oneTimeTokenLogin((ott) -> ott
.tokenGenerationSuccessHandler(ottSuccessHandler)
);
// @formatter:on
return http.build();
}
@Bean
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
return new TestOneTimeTokenGenerationSuccessHandler();
}
}
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@Import(UserDetailsServiceConfig.class)
@@ -57,7 +57,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@ -245,14 +244,6 @@ public class Saml2LoginConfigurerTests {
performSaml2Login("ROLE_AUTH_MANAGER");
}
// gh-19128
@Test
public void saml2LoginWhenBuilderBeanWithBasePathThenAuthenticateUriIgnoresBasePath() throws Exception {
this.spring.register(Saml2LoginBuilderBeanConfig.class).autowire();
MvcResult result = this.mvc.perform(get("/saml2/authenticate/registration-id")).andReturn();
assertThat(result.getResponse().getRedirectedUrl()).contains("SAMLRequest");
}
@Test
public void authenticationRequestWhenAuthenticationRequestResolverBeanThenUses() throws Exception {
this.spring.register(CustomAuthenticationRequestResolverBean.class).autowire();
@@ -531,33 +522,6 @@ public class Saml2LoginConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
static class Saml2LoginBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.saml2Login(Customizer.withDefaults());
// @formatter:on
return http.build();
}
}
@Configuration
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
@@ -49,7 +49,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.saml2.core.Saml2Utils;
@@ -197,17 +196,6 @@ public class Saml2LogoutConfigurerTests {
verify(logoutHandler).logout(any(), any(), any());
}
// gh-19128
@Test
public void saml2LogoutWhenBuilderBeanWithBasePathThenLogoutUrlIgnoresBasePath() throws Exception {
this.spring.register(Saml2LogoutBuilderBeanConfig.class).autowire();
MvcResult result = this.mvc.perform(post("/logout").with(authentication(this.user)).with(csrf()))
.andExpect(status().isFound())
.andReturn();
String location = result.getResponse().getHeader("Location");
assertThat(location).startsWith("https://ap.example.org/logout/saml2/request");
}
@Test
public void saml2LogoutWhenUnauthenticatedThenEntryPoint() throws Exception {
this.spring.register(Saml2LogoutDefaultsConfig.class).autowire();
@@ -589,32 +577,6 @@ public class Saml2LogoutConfigurerTests {
}
// gh-19128
@Configuration
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
static class Saml2LogoutBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.saml2Login(withDefaults())
.saml2Logout(withDefaults());
// @formatter:on
return http.build();
}
}
@Configuration
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
@@ -30,7 +30,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
import org.springframework.security.saml2.provider.service.metadata.OpenSaml5MetadataResolver;
import org.springframework.security.saml2.provider.service.metadata.RequestMatcherMetadataResponseResolver;
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResponse;
@@ -125,15 +124,6 @@ public class Saml2MetadataConfigurerTests {
this.mvc.perform(get("/saml2/metadata")).andExpect(status().isForbidden());
}
// gh-19128
@Test
void saml2MetadataWhenBuilderBeanWithBasePathThenMetadataUrlIgnoresBasePath() throws Exception {
this.spring.register(MetadataBuilderBeanConfig.class).autowire();
this.mvc.perform(get("/saml/metadata"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("md:EntityDescriptor")));
}
@EnableWebSecurity
@Configuration
@Import(RelyingPartyRegistrationConfig.class)
@@ -151,31 +141,6 @@ public class Saml2MetadataConfigurerTests {
}
// gh-19128
@EnableWebSecurity
@Configuration
@Import(RelyingPartyRegistrationConfig.class)
static class MetadataBuilderBeanConfig {
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
bean.setBasePath("/spring");
return bean;
}
@Bean
SecurityFilterChain filters(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.saml2Metadata((saml2) -> saml2.metadataUrl("/saml/metadata"));
return http.build();
// @formatter:on
}
}
@EnableWebSecurity
@Configuration
@Import(RelyingPartyRegistrationConfig.class)
@@ -107,7 +107,7 @@ public class ServerHttpSecurityConfigurationTests {
}
@Test
public void loadConfigWhenReactiveUserAuthenticationServiceConfiguredThenServerHttpSecurityExists() {
public void loadConfigWhenReactiveUserDetailsServiceConfiguredThenServerHttpSecurityExists() {
this.spring
.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
WebFluxSecurityConfiguration.class)
@@ -116,16 +116,6 @@ public class ServerHttpSecurityConfigurationTests {
assertThat(serverHttpSecurity).isNotNull();
}
@Test
public void loadConfigWhenOnlyReactiveUserDetailsServiceConfiguredThenServerHttpSecurityExists() {
this.spring
.register(ServerHttpSecurityConfiguration.class, ReactiveUserDetailsServiceOnlyTestConfiguration.class,
WebFluxSecurityConfiguration.class)
.autowire();
ServerHttpSecurity serverHttpSecurity = this.spring.getContext().getBean(ServerHttpSecurity.class);
assertThat(serverHttpSecurity).isNotNull();
}
@Test
public void loadConfigWhenProxyingEnabledAndSubclassThenServerHttpSecurityExists() {
this.spring
@@ -591,14 +581,4 @@ public class ServerHttpSecurityConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class ReactiveUserDetailsServiceOnlyTestConfiguration {
@Bean
static ReactiveUserDetailsService userDetailsService() {
return (username) -> Mono.just(PasswordEncodedUser.user());
}
}
}
@@ -65,7 +65,7 @@ public class XsdDocumentedTests {
String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd";
String schemaDocumentLocation = "org/springframework/security/config/spring-security-7.0.xsd";
String schemaDocumentLocation = "org/springframework/security/config/spring-security-7.1.xsd";
XmlSupport xml = new XmlSupport();
@@ -151,8 +151,8 @@ public class XsdDocumentedTests {
.list((dir, name) -> name.endsWith(".xsd"));
// @formatter:on
assertThat(schemas.length)
.withFailMessage("the count is equal to 28, if not then schemaDocument needs updating")
.isEqualTo(28);
.withFailMessage("the count is equal to 29, if not then schemaDocument needs updating")
.isEqualTo(29);
}
/**
@@ -28,17 +28,14 @@ import jakarta.servlet.http.HttpSession;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.session.SessionLimit;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
@@ -153,16 +150,6 @@ public class HttpHeadersConfigTests {
// @formatter:on
}
@Test
public void requestWhenHeadersEagerlyConfiguredThenHeadersAreWritten() throws Exception {
this.spring.configLocations(this.xml("HeadersEagerlyConfigured")).autowire();
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
public void requestWhenFrameOptionsConfiguredThenIncludesHeader() throws Exception {
Map<String, String> headers = new HashMap<>(defaultHeaders);
@@ -968,18 +955,6 @@ public class HttpHeadersConfigTests {
}
public static class EagerHeadersBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof HeaderWriterFilter headerWriterFilter) {
headerWriterFilter.setShouldWriteHeadersEagerly(true);
}
return bean;
}
}
public static class CustomSessionLimit implements SessionLimit {
@Override
@@ -314,78 +314,6 @@ public class InterceptUrlConfigTests {
.autowire());
}
@Test
public void requestWhenUsingDefaultMatcherAndServletPathThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("DefaultMatcherServletPath")).autowire();
// @formatter:off
this.mvc.perform(get("/spring/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWhenUsingDefaultMatcherAndServletPathAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
throws Exception {
this.spring.configLocations(this.xml("DefaultMatcherServletPathAuthorizationManager")).autowire();
// @formatter:off
this.mvc.perform(get("/spring/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isOk());
// @formatter:on
assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
}
@Test
public void requestWhenUsingRegexMatcherThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("RegexMatcher")).autowire();
// @formatter:off
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/other").with(userCredentials()))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void requestWhenUsingRegexMatcherAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
throws Exception {
this.spring.configLocations(this.xml("RegexMatcherAuthorizationManager")).autowire();
// @formatter:off
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/other").with(userCredentials()))
.andExpect(status().isNotFound());
// @formatter:on
assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
}
@Test
public void requestWhenUsingCiRegexMatcherThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("CiRegexMatcher")).autowire();
// @formatter:off
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/PATH").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void requestWhenUsingCiRegexMatcherAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
throws Exception {
this.spring.configLocations(this.xml("CiRegexMatcherAuthorizationManager")).autowire();
// @formatter:off
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/PATH").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
}
@Test
public void requestWhenUsingFilterAllDispatcherTypesAndAuthorizationManagerThenAuthorizesRequestsAccordingly()
throws Exception {
@@ -19,7 +19,6 @@ package org.springframework.security.config.http;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -989,7 +988,7 @@ public class MiscHttpConfigTests {
@GetMapping("/username")
String username() {
Subject subject = Subject.getSubject(AccessController.getContext());
Subject subject = Subject.current();
return subject.getPrincipals().iterator().next().getName();
}
@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2004-present 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http auto-config="true">
<headers/>
<intercept-url pattern="/**" access="permitAll"/>
</http>
<b:bean class="org.springframework.security.config.http.HttpHeadersConfigTests.EagerHeadersBeanPostProcessor"/>
<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
<b:import resource="userservice.xml"/>
</b:beans>
@@ -24,7 +24,7 @@
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http request-matcher="path" use-authorization-manager="false">
<http request-matcher="ant" use-authorization-manager="false">
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
<http-basic/>
</http>
@@ -24,7 +24,7 @@
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http request-matcher="path">
<http request-matcher="ant">
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
<http-basic/>
</http>
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2004-present 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http request-matcher="ciRegex" use-authorization-manager="false">
<intercept-url pattern="\A/PATH\Z" access="denyAll"/>
<intercept-url pattern="\A/.*\Z" access="permitAll"/>
<http-basic/>
</http>
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
</b:beans>
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2004-present 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http request-matcher="ciRegex">
<intercept-url pattern="\A/PATH\Z" access="denyAll"/>
<intercept-url pattern="\A/.*\Z" access="permitAll"/>
<http-basic/>
</http>
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
</b:beans>
@@ -26,11 +26,8 @@
<http use-authorization-manager="false">
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
<intercept-url pattern="/**" access="permitAll"/>
<http-basic/>
</http>
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
</b:beans>
@@ -26,11 +26,8 @@
<http>
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
<intercept-url pattern="/**" access="permitAll"/>
<http-basic/>
</http>
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
</b:beans>
@@ -27,7 +27,7 @@
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<http auto-config="true" request-matcher="path" use-authorization-manager="false">
<http auto-config="true" request-matcher="mvc" use-authorization-manager="false">
<intercept-url pattern="/path" access="denyAll"/>
<http-basic/>
</http>
@@ -27,7 +27,7 @@
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<http auto-config="true" request-matcher="path">
<http auto-config="true" request-matcher="mvc">
<intercept-url pattern="/path" access="denyAll"/>
<http-basic/>
</http>
@@ -27,7 +27,7 @@
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<http auto-config="true" request-matcher="path" use-authorization-manager="false">
<http auto-config="true" request-matcher="mvc" use-authorization-manager="false">
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
<http-basic/>
</http>
@@ -27,7 +27,7 @@
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<http auto-config="true" request-matcher="path">
<http auto-config="true" request-matcher="mvc">
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
<http-basic/>
</http>
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2004-present 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http request-matcher="regex" use-authorization-manager="false">
<intercept-url pattern="\A/path\Z" access="denyAll"/>
<intercept-url pattern="\A/.*\Z" access="permitAll"/>
<http-basic/>
</http>
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
</b:beans>
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2004-present 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.
-->
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<http request-matcher="regex">
<intercept-url pattern="\A/path\Z" access="denyAll"/>
<intercept-url pattern="\A/.*\Z" access="permitAll"/>
<http-basic/>
</http>
<b:bean name="path" class="org.springframework.security.config.http.InterceptUrlConfigTests.PathController"/>
<b:import resource="userservice.xml"/>
</b:beans>

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