Compare commits
198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d5b0c4627 | |||
| 45ce971d6c | |||
| 095cc3bf74 | |||
| 92fd945b02 | |||
| d0b0b5a252 | |||
| 601dfb2764 | |||
| b88ddc8d0d | |||
| 688b6ca733 | |||
| 6b028cfe8e | |||
| d912393280 | |||
| ba8360671c | |||
| bf7d86722f | |||
| e37f83884b | |||
| 3071459fe4 | |||
| 03c081bb46 | |||
| 540fbdb189 | |||
| cea004b555 | |||
| 4c011887bd | |||
| 938d1f38b9 | |||
| 54f294fe6e | |||
| fa10e74d76 | |||
| 0a8cdc32d5 | |||
| 5a51d63419 | |||
| ee7c579644 | |||
| b92f4e7ed2 | |||
| 9dff826c9f | |||
| ee2702254e | |||
| f0ad037099 | |||
| 8d426bd28f | |||
| a8a859ec0e | |||
| d467da7717 | |||
| 55ef3ce477 | |||
| bbb6f499c9 | |||
| 3386e077e6 | |||
| 10490a7b92 | |||
| f1e742dfc5 | |||
| 8e9480545e | |||
| 0eb5d8f356 | |||
| 3e238af024 | |||
| 29ed4dd724 | |||
| 218b13884f | |||
| fc2fd63793 | |||
| 199473fcb3 | |||
| 7903ad93c0 | |||
| fe65ef2626 | |||
| 2af6e1cf92 | |||
| e535803cc2 | |||
| eeb080a191 | |||
| b8c6b9fbff | |||
| 3cf0a1ccb7 | |||
| c2f0f7b6ab | |||
| 8cd2f36e84 | |||
| 517bc7cb65 | |||
| a2d407518c | |||
| 001d9df5ca | |||
| 818a7831dd | |||
| 0eba9de7d4 | |||
| 70fc8fef3a | |||
| 46027974dd | |||
| 338786bab9 | |||
| d7ecb8fdcf | |||
| a9f9eba6ca | |||
| 1a6f344196 | |||
| e771ec04b7 | |||
| f3656b4991 | |||
| 8f22fd4407 | |||
| 20493ef45f | |||
| e029b3ac6f | |||
| 55ab498518 | |||
| b0983e2f5e | |||
| 992d8ca79b | |||
| 4c012c59c9 | |||
| 2ee247f82e | |||
| 0496c02c30 | |||
| 93d8283e36 | |||
| 991b7d4dc2 | |||
| 64e863e7df | |||
| 4957c5a7e9 | |||
| 5b7c4ae8d8 | |||
| 8bafd94b1f | |||
| d244bcf76e | |||
| de23ade14b | |||
| afa3e2311c | |||
| 2a2f13fbd3 | |||
| db5310bee8 | |||
| dfed528851 | |||
| 6a6c7a7a78 | |||
| b591a0a757 | |||
| c5632ccd83 | |||
| a8b5c8fe02 | |||
| 054ff7421b | |||
| 6e30cd5417 | |||
| c7d52242fb | |||
| 6f6dbd5728 | |||
| 99eb7b1e5c | |||
| 89467605ca | |||
| 9fa0a34b4c | |||
| a23be5e625 | |||
| c3240c4d2b | |||
| 3c0fd6d7ca | |||
| d526bb460f | |||
| 30975df0a7 | |||
| bd49ceb0ef | |||
| 1c8bbda7af | |||
| fb19143c91 | |||
| f906539fe4 | |||
| 18ab4dc2c8 | |||
| b07cd701c7 | |||
| ea8bd1a01d | |||
| 0a182f1f20 | |||
| 5e56877487 | |||
| 38356fda10 | |||
| 442d72ec12 | |||
| 7513c859bd | |||
| 1b3cf72fc9 | |||
| d7fbf3673a | |||
| ab3298e917 | |||
| 37b0813b26 | |||
| 0340e0e918 | |||
| fc5194d78b | |||
| e7203bf838 | |||
| 42e1e9fb67 | |||
| 91aee30906 | |||
| 8247d18122 | |||
| f942ead2eb | |||
| b970746a03 | |||
| 131d3741b2 | |||
| e7aa15cb81 | |||
| af73f85f66 | |||
| 39544e1b9e | |||
| d07d3a13d1 | |||
| bf6bed01af | |||
| 74c454a5c7 | |||
| 2206815ad9 | |||
| 6695505676 | |||
| 6b4649ad3e | |||
| 7ace59c411 | |||
| 1cfb3033e9 | |||
| 021f84b2df | |||
| e5b934d1a5 | |||
| e3f1690396 | |||
| 1fb335c3b1 | |||
| cd2be2fc1c | |||
| feb3e9c3cc | |||
| 95d31a3754 | |||
| ef7bb7d334 | |||
| 9f8ac34c3b | |||
| 3f66d8b770 | |||
| ea26031a4d | |||
| b1d98491cf | |||
| c64747ce5f | |||
| cd4ad01742 | |||
| 0a035caa57 | |||
| ab8b139278 | |||
| e19c34771b | |||
| 318b4a785c | |||
| c73696f129 | |||
| 35d103843b | |||
| 8746ef746c | |||
| e72c39cabc | |||
| a8ca5b7d42 | |||
| afa5804170 | |||
| 15dd96bddb | |||
| 6b2e0444dd | |||
| 577d294fdc | |||
| 0993e5735e | |||
| 048b6bdd88 | |||
| 6e9b4f86a4 | |||
| 38b66e8407 | |||
| 9e5b3d9ea1 | |||
| 7563932106 | |||
| 48f958cbbf | |||
| 30d6b3a02b | |||
| cfe13c7c76 | |||
| 3336f5f2ec | |||
| 565896404c | |||
| 91d8a04ec2 | |||
| 8254f589b8 | |||
| 3f773abf7c | |||
| 92b7c41f2f | |||
| 8692185de1 | |||
| 7ca0f7723e | |||
| a612522ecd | |||
| fe138d6434 | |||
| 93ae52aa58 | |||
| 43fe5f6b46 | |||
| f47f81351e | |||
| 0d47870928 | |||
| da4362111a | |||
| 1ddccd8a39 | |||
| 2825aa3ff1 | |||
| ec06f08bb6 | |||
| 0a6883c586 | |||
| c07a2e57bd | |||
| 5a7d93ee3b | |||
| a3b57c470f | |||
| d1a32b4b62 | |||
| 3833650d33 |
+117
-31
@@ -1,12 +1,10 @@
|
||||
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
|
||||
updates:
|
||||
# 6.5.x
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 6.5.x
|
||||
directory: /
|
||||
@@ -17,7 +15,6 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -34,36 +31,28 @@ updates:
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 6.4.x
|
||||
- package-ecosystem: npm
|
||||
target-branch: 6.5.x
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
- package-ecosystem: github-actions
|
||||
target-branch: 6.5.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '03:00'
|
||||
timezone: Etc/UTC
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- '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
|
||||
- 'in: build'
|
||||
|
||||
# 7.0.x
|
||||
- package-ecosystem: gradle
|
||||
target-branch: main
|
||||
target-branch: 7.0.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
@@ -72,7 +61,6 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -93,16 +81,55 @@ updates:
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
|
||||
- package-ecosystem: npm
|
||||
target-branch: docs-build
|
||||
target-branch: 7.0.x
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
- package-ecosystem: github-actions
|
||||
target-branch: 7.0.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
|
||||
# main
|
||||
- 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: main
|
||||
directory: /docs
|
||||
@@ -110,4 +137,63 @@ updates:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
- package-ecosystem: github-actions
|
||||
target-branch: main
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
|
||||
# docs-build
|
||||
- package-ecosystem: gradle
|
||||
target-branch: docs-build
|
||||
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: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
- package-ecosystem: github-actions
|
||||
target-branch: docs-build
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Dependabot Auto-Merge
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security'
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
run: gh pr merge --auto --merge "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
@@ -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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
jdk: [ 17 ]
|
||||
jdk: [ 25 ]
|
||||
with:
|
||||
runs-on: ${{ matrix.os }}
|
||||
java-version: ${{ matrix.jdk }}
|
||||
@@ -29,23 +29,25 @@ 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@releases/v1
|
||||
with:
|
||||
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
default-publish-milestones-central: true
|
||||
java-version: 25
|
||||
secrets: inherit
|
||||
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@releases/v1
|
||||
with:
|
||||
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
java-version: 25
|
||||
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@releases/v1
|
||||
with:
|
||||
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
|
||||
project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
|
||||
@@ -53,6 +55,7 @@ jobs:
|
||||
release-repo-url: https://repo1.maven.org/maven2
|
||||
artifact-path: org/springframework/security/spring-security-core
|
||||
slack-announcing-id: spring-security-announcing
|
||||
java-version: 25
|
||||
secrets: inherit
|
||||
send-notification:
|
||||
name: Send Notification
|
||||
@@ -61,6 +64,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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- 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."
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
if: github.repository_owner == 'spring-projects'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: docs-build
|
||||
fetch-depth: 1
|
||||
|
||||
@@ -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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
with:
|
||||
should-perform-release: true
|
||||
project-version: ${{ inputs.version }}
|
||||
|
||||
@@ -19,11 +19,11 @@ 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up JDK 17
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Set up JDK 25
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '25'
|
||||
distribution: 'temurin'
|
||||
- name: Set up Gradle
|
||||
uses: gradle/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
|
||||
|
||||
@@ -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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -11,11 +11,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
||||
uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5
|
||||
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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
||||
uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5
|
||||
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@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
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@415e2b11a766ba64799fffb5c97a4f7e17f677cf
|
||||
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@415e2b11a766ba64799fffb5c97a4f7e17f677cf
|
||||
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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"java.import.gradle.enabled": false
|
||||
"java.gradle.buildServer.enabled": "off"
|
||||
}
|
||||
|
||||
-21
@@ -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.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
plugins {
|
||||
id 'compile-warnings-error'
|
||||
id 'javadoc-warnings-error'
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
|
||||
+3
-1
@@ -53,7 +53,9 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @deprecated Use {@link EnableMethodSecurity} or publish interceptors directly
|
||||
* @deprecated Use
|
||||
* <code>org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity</code>
|
||||
* or publish interceptors directly
|
||||
*/
|
||||
@NullUnmarked
|
||||
@Deprecated
|
||||
|
||||
-1
@@ -35,7 +35,6 @@ import org.springframework.security.web.FilterInvocation;
|
||||
*/
|
||||
@Deprecated
|
||||
@NullUnmarked
|
||||
@SuppressWarnings("serial")
|
||||
class WebExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<FilterInvocation> {
|
||||
|
||||
private final Expression authorizeExpression;
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
plugins {
|
||||
id 'compile-warnings-error'
|
||||
id 'javadoc-warnings-error'
|
||||
id 'security-nullability'
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.springframework.security.core.Authentication;
|
||||
/**
|
||||
* Used by Spring Security's expression-based access control implementation to evaluate
|
||||
* permissions for a particular object using the ACL module. Similar in behaviour to
|
||||
* {@link org.springframework.security.acls.AclEntryVoter AclEntryVoter}.
|
||||
* <code> org.springframework.security.acls.AclEntryVoter AclEntryVoter </code>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
|
||||
+5
-3
@@ -18,6 +18,8 @@ package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
@@ -36,7 +38,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
|
||||
private Permission permission;
|
||||
|
||||
private final Serializable id;
|
||||
private final @Nullable Serializable id;
|
||||
|
||||
private final Sid sid;
|
||||
|
||||
@@ -46,7 +48,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
|
||||
private final boolean granting;
|
||||
|
||||
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||
public AccessControlEntryImpl(@Nullable Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||
boolean auditSuccess, boolean auditFailure) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
@@ -133,7 +135,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
public @Nullable Serializable getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -99,7 +99,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Authentication authentication = context.getAuthentication();
|
||||
// Check if authorized by virtue of ACL ownership
|
||||
Sid currentUser = createCurrentUser(authentication);
|
||||
if (currentUser.equals(acl.getOwner())
|
||||
Sid owner = acl.getOwner();
|
||||
if (owner != null && currentUser.equals(owner)
|
||||
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
||||
return;
|
||||
}
|
||||
@@ -108,8 +109,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy
|
||||
.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities);
|
||||
if (acl.getOwner() instanceof GrantedAuthoritySid
|
||||
&& authorities.contains(((GrantedAuthoritySid) acl.getOwner()).getGrantedAuthority())) {
|
||||
if (owner instanceof GrantedAuthoritySid
|
||||
&& authorities.contains(((GrantedAuthoritySid) owner).getGrantedAuthority())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAcl;
|
||||
@@ -41,7 +43,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
private Acl parentAcl;
|
||||
private @Nullable Acl parentAcl;
|
||||
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
@@ -54,10 +56,10 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
private Serializable id;
|
||||
|
||||
// OwnershipAcl
|
||||
private Sid owner;
|
||||
private @Nullable Sid owner;
|
||||
|
||||
// includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||
private List<Sid> loadedSids = null;
|
||||
private @Nullable List<Sid> loadedSids = null;
|
||||
|
||||
private boolean entriesInheriting = true;
|
||||
|
||||
@@ -97,8 +99,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* @param owner the owner (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting,
|
||||
Sid owner) {
|
||||
PermissionGrantingStrategy grantingStrategy, @Nullable Acl parentAcl, @Nullable List<Sid> loadedSids,
|
||||
boolean entriesInheriting, Sid owner) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
@@ -117,7 +119,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* Private no-argument constructor for use by reflection-based persistence tools along
|
||||
* with field-level access.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@SuppressWarnings({ "unused", "NullAway.Init" })
|
||||
private AclImpl() {
|
||||
}
|
||||
|
||||
@@ -199,7 +201,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
public boolean isSidLoaded(@Nullable List<Sid> sids) {
|
||||
// If loadedSides is null, this indicates all SIDs were loaded
|
||||
// Also return true if the caller didn't specify a SID to find
|
||||
if ((this.loadedSids == null) || (sids == null) || sids.isEmpty()) {
|
||||
@@ -238,19 +240,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sid getOwner() {
|
||||
public @Nullable Sid getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(Acl newParent) {
|
||||
public void setParent(@Nullable Acl newParent) {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
||||
this.parentAcl = newParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl getParentAcl() {
|
||||
public @Nullable Acl getParentAcl() {
|
||||
return this.parentAcl;
|
||||
}
|
||||
|
||||
|
||||
+10
-4
@@ -18,6 +18,8 @@ package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
@@ -78,13 +80,13 @@ public class SpringCacheBasedAclCache implements AclCache {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
public @Nullable MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
return getFromCache((Object) objectIdentity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
public @Nullable MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
return getFromCache((Object) pk);
|
||||
}
|
||||
@@ -101,12 +103,16 @@ public class SpringCacheBasedAclCache implements AclCache {
|
||||
this.cache.put(acl.getId(), acl);
|
||||
}
|
||||
|
||||
private MutableAcl getFromCache(Object key) {
|
||||
private @Nullable MutableAcl getFromCache(Object key) {
|
||||
Cache.ValueWrapper element = this.cache.get(key);
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
return initializeTransientFields((MutableAcl) element.get());
|
||||
Object value = element.get();
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return initializeTransientFields((MutableAcl) value);
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Basic implementation of access control lists (ACLs) interfaces.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.UUID;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
@@ -67,10 +68,10 @@ class AclClassIdUtils {
|
||||
* @return The identifier in the appropriate target Java type. Typically Long or UUID.
|
||||
* @throws SQLException
|
||||
*/
|
||||
Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
|
||||
if (isString(identifier) && hasValidClassIdType(resultSet)
|
||||
&& canConvertFromStringTo(classIdTypeFrom(resultSet))) {
|
||||
return convertFromStringTo((String) identifier, classIdTypeFrom(resultSet));
|
||||
@Nullable Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
|
||||
Class<? extends Serializable> classIdType = classIdTypeFrom(resultSet);
|
||||
if (isString(identifier) && classIdType != null && canConvertFromStringTo(classIdType)) {
|
||||
return convertFromStringTo((String) identifier, classIdType);
|
||||
}
|
||||
// Assume it should be a Long type
|
||||
return convertToLong(identifier);
|
||||
@@ -86,28 +87,38 @@ class AclClassIdUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Serializable> Class<T> classIdTypeFrom(ResultSet resultSet) throws SQLException {
|
||||
return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
|
||||
private @Nullable Class<? extends Serializable> classIdTypeFrom(ResultSet resultSet) throws SQLException {
|
||||
try {
|
||||
return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
log.debug("Unable to obtain the class id type", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Serializable> Class<T> classIdTypeFrom(String className) {
|
||||
private @Nullable Class<? extends Serializable> classIdTypeFrom(String className) {
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (Class) Class.forName(className);
|
||||
return Class.forName(className).asSubclass(Serializable.class);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
log.debug("Unable to find class id type on classpath", ex);
|
||||
return null;
|
||||
}
|
||||
catch (ClassCastException ex) {
|
||||
log.debug("Class id type is not a Serializable type", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> boolean canConvertFromStringTo(Class<T> targetType) {
|
||||
return this.conversionService.canConvert(String.class, targetType);
|
||||
}
|
||||
|
||||
private <T extends Serializable> T convertFromStringTo(String identifier, Class<T> targetType) {
|
||||
private <T extends Serializable> @Nullable T convertFromStringTo(String identifier, Class<T> targetType) {
|
||||
return this.conversionService.convert(identifier, targetType);
|
||||
}
|
||||
|
||||
@@ -121,7 +132,7 @@ class AclClassIdUtils {
|
||||
* exception occurred
|
||||
* @throws IllegalArgumentException if targetType is null
|
||||
*/
|
||||
private Long convertToLong(Serializable identifier) {
|
||||
private @Nullable Long convertToLong(Serializable identifier) {
|
||||
if (this.conversionService.canConvert(identifier.getClass(), Long.class)) {
|
||||
return this.conversionService.convert(identifier, Long.class);
|
||||
}
|
||||
@@ -140,10 +151,10 @@ class AclClassIdUtils {
|
||||
private static class StringToLongConverter implements Converter<String, Long> {
|
||||
|
||||
@Override
|
||||
public Long convert(String identifierAsString) {
|
||||
public Long convert(@Nullable String identifierAsString) {
|
||||
if (identifierAsString == null) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(Long.class), null, null);
|
||||
TypeDescriptor.valueOf(Long.class), identifierAsString, new NullPointerException());
|
||||
|
||||
}
|
||||
return Long.parseLong(identifierAsString);
|
||||
@@ -154,10 +165,10 @@ class AclClassIdUtils {
|
||||
private static class StringToUUIDConverter implements Converter<String, UUID> {
|
||||
|
||||
@Override
|
||||
public UUID convert(String identifierAsString) {
|
||||
public UUID convert(@Nullable String identifierAsString) {
|
||||
if (identifierAsString == null) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(UUID.class), null, null);
|
||||
TypeDescriptor.valueOf(UUID.class), identifierAsString, new NullPointerException());
|
||||
|
||||
}
|
||||
return UUID.fromString(identifierAsString);
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -224,7 +226,8 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* @param findNow Long-based primary keys to retrieve
|
||||
* @param sids
|
||||
*/
|
||||
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow, final List<Sid> sids) {
|
||||
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow,
|
||||
final @Nullable List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
String sql = computeRepeatingSql(this.lookupPrimaryKeysWhereClause, findNow.size());
|
||||
@@ -264,7 +267,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* automatically create entries if required)
|
||||
*/
|
||||
@Override
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids) {
|
||||
Assert.isTrue(this.batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
// Map<ObjectIdentity,Acl>
|
||||
@@ -323,7 +326,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* properly-configured parent ACLs.
|
||||
*/
|
||||
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities,
|
||||
List<Sid> sids) {
|
||||
@Nullable List<Sid> sids) {
|
||||
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
||||
|
||||
// contains Acls with StubAclParents
|
||||
@@ -399,8 +402,10 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
// Now we have the parent (if there is one), create the true AclImpl
|
||||
Sid owner = inputAcl.getOwner();
|
||||
Assert.isTrue(owner != null, "Owner is required");
|
||||
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), inputAcl.getId(), this.aclAuthorizationStrategy,
|
||||
this.grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
this.grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), owner);
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
|
||||
@@ -506,9 +511,9 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
private final Map<Serializable, Acl> acls;
|
||||
|
||||
private final List<Sid> sids;
|
||||
private final @Nullable List<Sid> sids;
|
||||
|
||||
ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||
ProcessResultSet(Map<Serializable, Acl> acls, @Nullable List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs cannot be null");
|
||||
this.acls = acls;
|
||||
this.sids = sids; // can be null
|
||||
@@ -579,6 +584,9 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
// target id type, e.g. UUID.
|
||||
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
|
||||
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
|
||||
if (identifier == null) {
|
||||
throw new IllegalStateException("Identifier cannot be null");
|
||||
}
|
||||
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
|
||||
.createObjectIdentity(identifier, rs.getString("class"));
|
||||
|
||||
@@ -670,7 +678,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
public boolean isSidLoaded(@Nullable List<Sid> sids) {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
@@ -98,7 +99,7 @@ public class JdbcAclService implements AclService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
public @Nullable List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
|
||||
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql,
|
||||
(rs, rowNum) -> mapObjectIdentityRow(rs), args);
|
||||
@@ -109,11 +110,14 @@ public class JdbcAclService implements AclService {
|
||||
String javaType = rs.getString("class");
|
||||
Serializable identifier = (Serializable) rs.getObject("obj_id");
|
||||
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
|
||||
if (identifier == null) {
|
||||
throw new IllegalStateException("Identifier cannot be null");
|
||||
}
|
||||
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
|
||||
public Acl readAclById(ObjectIdentity object, @Nullable List<Sid> sids) throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
|
||||
Assert.isTrue(map.containsKey(object),
|
||||
() -> "There should have been an Acl entry for ObjectIdentity " + object);
|
||||
@@ -131,7 +135,7 @@ public class JdbcAclService implements AclService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids)
|
||||
throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
|
||||
// Check every requested object identity was found (throw NotFoundException if
|
||||
|
||||
+40
-15
@@ -22,6 +22,8 @@ import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
@@ -120,6 +122,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
// Need to retrieve the current principal, in order to know who "owns" this ACL
|
||||
// (can be changed later on)
|
||||
Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||
Assert.isTrue(auth != null, "Authentication required");
|
||||
PrincipalSid sid = new PrincipalSid(auth);
|
||||
|
||||
// Create the acl_object_identity row
|
||||
@@ -155,9 +158,12 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
|
||||
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
|
||||
|
||||
Assert.state(acl.getId() != null, "ACL ID cannot be null");
|
||||
stmt.setLong(1, (Long) acl.getId());
|
||||
stmt.setInt(2, i);
|
||||
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true));
|
||||
Long sidPrimaryKey = createOrRetrieveSidPrimaryKey(entry.getSid(), true);
|
||||
Assert.state(sidPrimaryKey != null, "SID primary key cannot be null");
|
||||
stmt.setLong(3, sidPrimaryKey);
|
||||
stmt.setInt(4, entry.getPermission().getMask());
|
||||
stmt.setBoolean(5, entry.isGranting());
|
||||
stmt.setBoolean(6, entry.isAuditSuccess());
|
||||
@@ -189,11 +195,14 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
|
||||
protected @Nullable Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||
List<@Nullable Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
|
||||
|
||||
if (!classIds.isEmpty()) {
|
||||
return classIds.get(0);
|
||||
Long result = classIds.get(0);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
@@ -204,7 +213,9 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName());
|
||||
}
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
return this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
|
||||
Long result = this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
|
||||
Assert.state(result != null, "Failed to retrieve class primary key");
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -219,7 +230,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized
|
||||
* implementation.
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
protected @Nullable Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (sid instanceof PrincipalSid) {
|
||||
String sidName = ((PrincipalSid) sid).getPrincipal();
|
||||
@@ -240,16 +251,22 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
|
||||
List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidIsPrincipal,
|
||||
sidName);
|
||||
protected @Nullable Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal,
|
||||
boolean allowCreate) {
|
||||
List<@Nullable Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class,
|
||||
sidIsPrincipal, sidName);
|
||||
if (!sidIds.isEmpty()) {
|
||||
return sidIds.get(0);
|
||||
Long result = sidIds.get(0);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (allowCreate) {
|
||||
this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
return this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
|
||||
Long result = this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
|
||||
Assert.state(result != null, "Failed to retrieve sid primary key");
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -279,6 +296,9 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
}
|
||||
|
||||
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
|
||||
if (oidPrimaryKey == null) {
|
||||
throw new NotFoundException("Object identity not found: " + objectIdentity);
|
||||
}
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(oidPrimaryKey);
|
||||
@@ -319,10 +339,11 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param oid to find
|
||||
* @return the object identity or null if not found
|
||||
*/
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
protected @Nullable Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
return this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, oid.getType(),
|
||||
oid.getIdentifier().toString());
|
||||
Long result = this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class,
|
||||
oid.getType(), oid.getIdentifier().toString());
|
||||
return result;
|
||||
}
|
||||
catch (DataAccessException notFound) {
|
||||
return null;
|
||||
@@ -340,7 +361,11 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
|
||||
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity());
|
||||
if (oidPrimaryKey == null) {
|
||||
throw new NotFoundException("Object identity not found for ACL: " + acl.getObjectIdentity());
|
||||
}
|
||||
deleteEntries(oidPrimaryKey);
|
||||
|
||||
// Create this ACL's ACEs in the acl_entry table
|
||||
createEntries(acl);
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.security.acls.jdbc;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
@@ -42,6 +44,6 @@ public interface LookupStrategy {
|
||||
* {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used to
|
||||
* automatically create entries if required)
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids);
|
||||
|
||||
}
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* JDBC-based persistence of ACL information
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an individual permission assignment within an {@link Acl}.
|
||||
*
|
||||
@@ -36,7 +38,7 @@ public interface AccessControlEntry extends Serializable {
|
||||
* Obtains an identifier that represents this ACE.
|
||||
* @return the identifier, or <code>null</code> if unsaved
|
||||
*/
|
||||
Serializable getId();
|
||||
@Nullable Serializable getId();
|
||||
|
||||
Permission getPermission();
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.security.acls.model;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an access control list (ACL) for a domain object.
|
||||
*
|
||||
@@ -82,7 +84,7 @@ public interface Acl extends Serializable {
|
||||
* @return the owner (may be <tt>null</tt> if the implementation does not use
|
||||
* ownership concepts)
|
||||
*/
|
||||
Sid getOwner();
|
||||
@Nullable Sid getOwner();
|
||||
|
||||
/**
|
||||
* A domain object may have a parent for the purpose of ACL inheritance. If there is a
|
||||
@@ -103,7 +105,7 @@ public interface Acl extends Serializable {
|
||||
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not
|
||||
* have a parent)
|
||||
*/
|
||||
Acl getParentAcl();
|
||||
@Nullable Acl getParentAcl();
|
||||
|
||||
/**
|
||||
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down
|
||||
@@ -189,6 +191,6 @@ public interface Acl extends Serializable {
|
||||
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this
|
||||
* <tt>Acl</tt> instance
|
||||
*/
|
||||
boolean isSidLoaded(List<Sid> sids);
|
||||
boolean isSidLoaded(@Nullable List<Sid> sids);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.acls.jdbc.JdbcAclService;
|
||||
|
||||
/**
|
||||
@@ -31,9 +33,9 @@ public interface AclCache {
|
||||
|
||||
void evictFromCache(ObjectIdentity objectIdentity);
|
||||
|
||||
MutableAcl getFromCache(ObjectIdentity objectIdentity);
|
||||
@Nullable MutableAcl getFromCache(ObjectIdentity objectIdentity);
|
||||
|
||||
MutableAcl getFromCache(Serializable pk);
|
||||
@Nullable MutableAcl getFromCache(Serializable pk);
|
||||
|
||||
void putInCache(MutableAcl acl);
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.security.acls.model;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Provides retrieval of {@link Acl} instances.
|
||||
*
|
||||
@@ -32,7 +34,7 @@ public interface AclService {
|
||||
* @param parentIdentity to locate children of
|
||||
* @return the children (or <tt>null</tt> if none were found)
|
||||
*/
|
||||
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||
@Nullable List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(List)} except it returns only a single Acl.
|
||||
@@ -59,7 +61,7 @@ public interface AclService {
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
|
||||
Acl readAclById(ObjectIdentity object, @Nullable List<Sid> sids) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.
|
||||
@@ -98,6 +100,7 @@ public interface AclService {
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids)
|
||||
throws NotFoundException;
|
||||
|
||||
}
|
||||
|
||||
@@ -18,4 +18,7 @@
|
||||
* Interfaces and shared classes to manage access control lists (ACLs) for domain object
|
||||
* instances.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -24,4 +24,7 @@
|
||||
* older and more verbose attribute/voter/after-invocation approach from versions before
|
||||
* Spring Security 3.0.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -478,6 +478,7 @@ public class AclImplTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hashCodeWithoutStackOverFlow() throws Exception {
|
||||
Sid sid = new PrincipalSid("pSid");
|
||||
ObjectIdentity oid = new ObjectIdentityImpl("type", 1);
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@@ -46,7 +47,6 @@ import org.springframework.security.acls.model.Sid;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -109,7 +109,8 @@ public class JdbcAclServiceTests {
|
||||
List<ObjectIdentity> result = new ArrayList<>();
|
||||
result.add(new ObjectIdentityImpl(Object.class, "5577"));
|
||||
Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" };
|
||||
given(this.jdbcOperations.query(anyString(), any(RowMapper.class), eq(args))).willReturn(result);
|
||||
given(this.jdbcOperations.query(anyString(), ArgumentMatchers.<RowMapper<ObjectIdentity>>any(), eq(args)))
|
||||
.willReturn(result);
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L);
|
||||
List<ObjectIdentity> objectIdentities = this.aclService.findChildren(objectIdentity);
|
||||
assertThat(objectIdentities).hasSize(1);
|
||||
|
||||
+2
-4
@@ -80,11 +80,10 @@ public class SpringCacheBasedAclCacheTests {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new SpringCacheBasedAclCache(null, null, null));
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void cacheOperationsAclWithoutParent() {
|
||||
Cache cache = getCache();
|
||||
Map realCache = (Map) cache.getNativeCache();
|
||||
Map<?, ?> realCache = (Map<?, ?>) cache.getNativeCache();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100L);
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
|
||||
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
|
||||
@@ -116,11 +115,10 @@ public class SpringCacheBasedAclCacheTests {
|
||||
assertThat(realCache).isEmpty();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void cacheOperationsAclWithParent() throws Exception {
|
||||
Cache cache = getCache();
|
||||
Map realCache = (Map) cache.getNativeCache();
|
||||
Map<?, ?> realCache = (Map<?, ?>) cache.getNativeCache();
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'io.freefair.aspectj'
|
||||
apply plugin: 'compile-warnings-error'
|
||||
|
||||
compileAspectj {
|
||||
sourceCompatibility = "17"
|
||||
targetCompatibility = "17"
|
||||
ajcOptions.compilerArgs += ['-Xlint:ignore']
|
||||
}
|
||||
compileTestAspectj {
|
||||
sourceCompatibility = "17"
|
||||
targetCompatibility = "17"
|
||||
ajcOptions.compilerArgs += ['-Xlint:ignore']
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import io.spring.gradle.convention.SpringModulePlugin
|
||||
|
||||
apply plugin: 'io.spring.convention.bom'
|
||||
apply plugin: 'compile-warnings-error'
|
||||
|
||||
dependencies {
|
||||
constraints {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
plugins {
|
||||
id 'security-nullability'
|
||||
id 'javadoc-warnings-error'
|
||||
id 'compile-warnings-error'
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
-2
@@ -24,7 +24,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.apereo.cas.client.validation.TicketValidationException;
|
||||
import org.apereo.cas.client.validation.TicketValidator;
|
||||
import org.jspecify.annotations.NullUnmarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -166,7 +165,6 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
* @param authentication
|
||||
* @return
|
||||
*/
|
||||
@NullUnmarked
|
||||
private @Nullable String getServiceUrl(Authentication authentication) {
|
||||
String serviceUrl;
|
||||
if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-1
@@ -91,7 +91,8 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
|
||||
*/
|
||||
protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) {
|
||||
return WebUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null,
|
||||
this.serviceProperties.getArtifactParameter(), this.encodeServiceUrlWithSessionId);
|
||||
this.serviceProperties.getServiceParameter(), this.serviceProperties.getArtifactParameter(),
|
||||
this.encodeServiceUrlWithSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,8 @@ import trang.RncToXsd
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'trang'
|
||||
apply plugin: 'security-kotlin'
|
||||
apply plugin: 'test-compile-target-jdk25'
|
||||
apply plugin: 'javadoc-warnings-error'
|
||||
|
||||
configurations {
|
||||
opensaml5 {
|
||||
|
||||
+3
@@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@@ -98,12 +99,14 @@ public class LdapBindAuthenticationManagerFactoryITests {
|
||||
public void authenticationManagerFactoryWhenCustomUserDetailsContextMapperThenUsed() throws Exception {
|
||||
CustomUserDetailsContextMapperConfig.CONTEXT_MAPPER = new UserDetailsContextMapper() {
|
||||
@Override
|
||||
@NullMarked
|
||||
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
return User.withUsername("other").password("password").roles("USER").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NullMarked
|
||||
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -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.*");
|
||||
}
|
||||
|
||||
+5
-9
@@ -1881,7 +1881,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #securityMatchers(Customizer)} will not override previous
|
||||
* invocations of {@link #securityMatchers()}}, {@link #securityMatchers(Customizer)}
|
||||
* invocations of {@link #securityMatchers(Customizer)}
|
||||
* {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)}
|
||||
* </p>
|
||||
*
|
||||
@@ -2004,8 +2004,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* <p>
|
||||
* Invoking {@link #securityMatcher(RequestMatcher)} will override previous
|
||||
* invocations of {@link #securityMatcher(RequestMatcher)},
|
||||
* {@link #securityMatcher(String...)}, {@link #securityMatchers(Customizer)} and
|
||||
* {@link #securityMatchers()}
|
||||
* {@link #securityMatcher(String...)} and {@link #securityMatchers(Customizer)}
|
||||
* </p>
|
||||
* @param requestMatcher the {@link RequestMatcher} to use, for example,
|
||||
* {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")}
|
||||
@@ -2024,9 +2023,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #securityMatcher(String...)} will override previous invocations of
|
||||
* {@link #securityMatcher(String...)} (String)}},
|
||||
* {@link #securityMatcher(RequestMatcher)} ()}, {@link #securityMatchers(Customizer)}
|
||||
* (String)} and {@link #securityMatchers()} (String)}.
|
||||
* {@link #securityMatcher(String...)}, {@link #securityMatcher(RequestMatcher)} and
|
||||
* {@link #securityMatchers(Customizer)}.
|
||||
* </p>
|
||||
* @param patterns the pattern to match on (i.e. "/admin/**")
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
@@ -2035,9 +2033,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));
|
||||
}
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
*
|
||||
* <p>
|
||||
* Typically this method is invoked automatically within the framework from
|
||||
* {@link WebSecurityConfiguration#springSecurityFilterChain()}
|
||||
* {@link WebSecurityConfiguration#springSecurityFilterChain(ObjectProvider)}
|
||||
* </p>
|
||||
* @param securityFilterChainBuilder the builder to use to create the
|
||||
* {@link SecurityFilterChain} instances
|
||||
|
||||
+2
-1
@@ -39,6 +39,7 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
|
||||
* other than applying this {@link SecurityConfigurer}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author DingHao
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
@@ -158,7 +159,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
this.authenticationFilter.afterPropertiesSet();
|
||||
http.addFilter(this.authenticationFilter);
|
||||
http.addFilter(postProcess(this.authenticationFilter));
|
||||
}
|
||||
|
||||
private String getKey() {
|
||||
|
||||
-3
@@ -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) {
|
||||
|
||||
+4
-3
@@ -47,8 +47,8 @@ import org.springframework.util.Assert;
|
||||
* The following configuration options are available:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #authorizationCodeGrant()} - support for the OAuth 2.0 Authorization Code
|
||||
* Grant</li>
|
||||
* <li>{@link #authorizationCodeGrant(Customizer)} - support for the OAuth 2.0
|
||||
* Authorization Code Grant</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
@@ -59,7 +59,8 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following {@code Filter}'s are populated for {@link #authorizationCodeGrant()}:
|
||||
* The following {@code Filter}'s are populated for
|
||||
* {@link #authorizationCodeGrant(Customizer)}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link OAuth2AuthorizationRequestRedirectFilter}</li>
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+4
-2
@@ -21,6 +21,7 @@ import java.util.function.Function;
|
||||
import org.opensaml.core.Version;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
@@ -42,7 +43,8 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <p>
|
||||
* Defaults are provided for all configuration options with the only required
|
||||
* configuration being a {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository}.
|
||||
* configuration being a
|
||||
* {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository(HttpSecurityBuilder)}.
|
||||
* Alternatively, a {@link RelyingPartyRegistrationRepository} {@code @Bean} may be
|
||||
* registered instead.
|
||||
*
|
||||
@@ -67,7 +69,7 @@ import org.springframework.util.Assert;
|
||||
* </ul>
|
||||
*
|
||||
* @since 6.1
|
||||
* @see HttpSecurity#saml2Metadata()
|
||||
* @see HttpSecurity#saml2Metadata(Customizer)
|
||||
* @see Saml2MetadataFilter
|
||||
* @see RelyingPartyRegistrationRepository
|
||||
*/
|
||||
|
||||
+1
-3
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-12
@@ -2162,7 +2162,7 @@ public class ServerHttpSecurity {
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.6
|
||||
* @see #passwordManagement()
|
||||
* @see #passwordManagement(Customizer)
|
||||
*/
|
||||
public final class PasswordManagementSpec {
|
||||
|
||||
@@ -2663,7 +2663,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures cache control headers
|
||||
*
|
||||
* @see #cache()
|
||||
* @see HeaderSpec#cache(Customizer)
|
||||
*/
|
||||
public final class CacheSpec {
|
||||
|
||||
@@ -2684,7 +2684,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* The content type headers
|
||||
*
|
||||
* @see #contentTypeOptions()
|
||||
* @see HeaderSpec#contentTypeOptions(Customizer)
|
||||
*/
|
||||
public final class ContentTypeOptionsSpec {
|
||||
|
||||
@@ -2705,7 +2705,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures frame options response header
|
||||
*
|
||||
* @see #frameOptions()
|
||||
* @see HeaderSpec#frameOptions(Customizer)
|
||||
*/
|
||||
public final class FrameOptionsSpec {
|
||||
|
||||
@@ -2737,7 +2737,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures Strict Transport Security response header
|
||||
*
|
||||
* @see #hsts()
|
||||
* @see HeaderSpec#hsts(Customizer)
|
||||
*/
|
||||
public final class HstsSpec {
|
||||
|
||||
@@ -2796,7 +2796,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures x-xss-protection response header
|
||||
*
|
||||
* @see #xssProtection()
|
||||
* @see HeaderSpec#xssProtection(Customizer)
|
||||
*/
|
||||
public final class XssProtectionSpec {
|
||||
|
||||
@@ -2830,7 +2830,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Content-Security-Policy} response header.
|
||||
*
|
||||
* @since 5.1
|
||||
* @see #contentSecurityPolicy(String)
|
||||
* @see HeaderSpec#contentSecurityPolicy(Customizer)
|
||||
*/
|
||||
public final class ContentSecurityPolicySpec {
|
||||
|
||||
@@ -2884,8 +2884,7 @@ public class ServerHttpSecurity {
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
* @deprecated For removal in 7.0. Use {@link #featurePolicy(Customizer)}
|
||||
* instead
|
||||
* @deprecated For removal in 7.0. Use {@link #featurePolicy(String)} instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
@@ -2898,7 +2897,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Permissions-Policy} response header.
|
||||
*
|
||||
* @since 5.5
|
||||
* @see #permissionsPolicy()
|
||||
* @see HeaderSpec#permissionsPolicy(Customizer)
|
||||
*/
|
||||
public final class PermissionsPolicySpec {
|
||||
|
||||
@@ -2921,8 +2920,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Referrer-Policy} response header.
|
||||
*
|
||||
* @since 5.1
|
||||
* @see #referrerPolicy()
|
||||
* @see #referrerPolicy(ReferrerPolicy)
|
||||
* @see HeaderSpec#referrerPolicy(Customizer)
|
||||
*/
|
||||
public final class ReferrerPolicySpec {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -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 }
|
||||
|
||||
+20
-16
@@ -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>
|
||||
|
||||
+1361
File diff suppressed because it is too large
Load Diff
+3849
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
+9
-56
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
-62
@@ -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 {
|
||||
|
||||
+45
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@@ -23,6 +24,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.config.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@@ -34,11 +37,14 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication;
|
||||
@@ -101,6 +107,45 @@ public class AnonymousConfigurerTests {
|
||||
this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("myAnonymousUser"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void anonymousAuthenticationWhenUsingAuthenticationDetailsSourceRefThenMatchesNamespace() throws Exception {
|
||||
this.spring.register(AuthenticationDetailsSourceAnonymousConfig.class).autowire();
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> source = this.spring.getContext()
|
||||
.getBean(AuthenticationDetailsSource.class);
|
||||
this.mockMvc.perform(get("/"));
|
||||
verify(source).buildDetails(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class AuthenticationDetailsSourceAnonymousConfig {
|
||||
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = mock(
|
||||
AuthenticationDetailsSource.class);
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
return http.anonymous((anonymous) -> anonymous
|
||||
.withObjectPostProcessor(new ObjectPostProcessor<AnonymousAuthenticationFilter>() {
|
||||
|
||||
@Override
|
||||
public <O extends AnonymousAuthenticationFilter> O postProcess(O object) {
|
||||
object.setAuthenticationDetailsSource(
|
||||
AuthenticationDetailsSourceAnonymousConfig.this.authenticationDetailsSource);
|
||||
return object;
|
||||
}
|
||||
|
||||
})).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource() {
|
||||
return this.authenticationDetailsSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
|
||||
-38
@@ -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 {
|
||||
|
||||
-43
@@ -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 {
|
||||
|
||||
-105
@@ -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
@@ -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 {
|
||||
|
||||
-34
@@ -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 {
|
||||
|
||||
-41
@@ -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 {
|
||||
|
||||
-69
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-38
@@ -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 {
|
||||
|
||||
+4
-140
@@ -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()
|
||||
|
||||
+2
-2
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+4
-170
@@ -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) ->
|
||||
|
||||
+7
-15
@@ -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();
|
||||
|
||||
-49
@@ -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)
|
||||
|
||||
-36
@@ -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)
|
||||
|
||||
+3
-39
@@ -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();
|
||||
@@ -421,7 +409,9 @@ public class Saml2LogoutConfigurerTests {
|
||||
logoutRequest.setIssueInstant(Instant.now());
|
||||
given(getBean(Saml2LogoutRequestValidator.class).validate(any()))
|
||||
.willReturn(Saml2LogoutValidatorResult.success());
|
||||
Saml2LogoutResponse logoutResponse = Saml2LogoutResponse.withRelyingPartyRegistration(registration).build();
|
||||
Saml2LogoutResponse logoutResponse = Saml2LogoutResponse.withRelyingPartyRegistration(registration)
|
||||
.samlResponse("samlResponse")
|
||||
.build();
|
||||
given(getBean(Saml2LogoutResponseResolver.class).resolve(any(), any())).willReturn(logoutResponse);
|
||||
this.mvc.perform(post("/logout/saml2/slo").param("SAMLRequest", "samlRequest").with(authentication(this.user)))
|
||||
.andReturn();
|
||||
@@ -589,32 +579,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)
|
||||
|
||||
-35
@@ -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)
|
||||
|
||||
+1
-21
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
-25
@@ -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
|
||||
|
||||
-72
@@ -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 {
|
||||
|
||||
+1
-2
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -306,7 +306,9 @@ public class Saml2LogoutBeanDefinitionParserTests {
|
||||
logoutRequest.setIssueInstant(Instant.now());
|
||||
given(getBean(Saml2LogoutRequestValidator.class).validate(any()))
|
||||
.willReturn(Saml2LogoutValidatorResult.success());
|
||||
Saml2LogoutResponse logoutResponse = Saml2LogoutResponse.withRelyingPartyRegistration(registration).build();
|
||||
Saml2LogoutResponse logoutResponse = Saml2LogoutResponse.withRelyingPartyRegistration(registration)
|
||||
.samlResponse("samlResponse")
|
||||
.build();
|
||||
given(getBean(Saml2LogoutResponseResolver.class).resolve(any(), any())).willReturn(logoutResponse);
|
||||
this.mvc
|
||||
.perform(post("/logout/saml2/slo").param("SAMLRequest", "samlRequest").with(authentication(this.saml2User)))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user