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,14 +14,12 @@ permissions:
|
||||
jobs:
|
||||
snapshot-test:
|
||||
name: Test Against Snapshots
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- java-version: 21-ea
|
||||
toolchain: 21
|
||||
- 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.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
|
||||
@@ -33,6 +31,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Notification
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@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 }}
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
jdk: [ 17 ]
|
||||
jdk: [ 25 ]
|
||||
with:
|
||||
runs-on: ${{ matrix.os }}
|
||||
java-version: ${{ matrix.jdk }}
|
||||
@@ -30,22 +30,24 @@ jobs:
|
||||
deploy-artifacts:
|
||||
name: Deploy Artifacts
|
||||
needs: [ build]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
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@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
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
|
||||
|
||||
@@ -16,7 +16,7 @@ permissions:
|
||||
jobs:
|
||||
perform-release:
|
||||
name: Perform Release
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@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 }}
|
||||
|
||||
@@ -20,10 +20,10 @@ jobs:
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Set up JDK 17
|
||||
- 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
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up gradle
|
||||
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
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Set up gradle
|
||||
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
|
||||
|
||||
@@ -11,7 +11,7 @@ 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
|
||||
|
||||
@@ -16,7 +16,7 @@ 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
|
||||
name: Update
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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,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) {
|
||||
|
||||
@@ -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.*");
|
||||
}
|
||||
|
||||
+4
-6
@@ -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
|
||||
|
||||
+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() {
|
||||
|
||||
+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>
|
||||
|
||||
+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
|
||||
*/
|
||||
|
||||
+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
|
||||
|
||||
+1361
File diff suppressed because it is too large
Load Diff
+3849
File diff suppressed because it is too large
Load Diff
+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
|
||||
|
||||
+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
|
||||
|
||||
+3
-1
@@ -409,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();
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+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)))
|
||||
|
||||
+2
-2
@@ -278,7 +278,7 @@ public class LogoutSpecTests {
|
||||
|
||||
private static class InMemorySecurityContextRepository implements ServerSecurityContextRepository {
|
||||
|
||||
@Nullable private SecurityContext savedContext;
|
||||
private @Nullable SecurityContext savedContext;
|
||||
|
||||
@Override
|
||||
public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
|
||||
@@ -291,7 +291,7 @@ public class LogoutSpecTests {
|
||||
return Mono.justOrEmpty(this.savedContext);
|
||||
}
|
||||
|
||||
@Nullable private SecurityContext getSavedContext() {
|
||||
private @Nullable SecurityContext getSavedContext() {
|
||||
return this.savedContext;
|
||||
}
|
||||
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user