Compare commits
123 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53bc6a7796 | |||
| aed95aa2b1 | |||
| 7b57a4a3bb | |||
| 11047960ad | |||
| 3d4e20597a | |||
| 4c40eeb89e | |||
| ff1e925c08 | |||
| 7b309cf271 | |||
| 51a1f88ddf | |||
| 762d8f19e5 | |||
| c9d623966f | |||
| 81bd52ae48 | |||
| 25b6af2738 | |||
| 95987bffc1 | |||
| e96203d578 | |||
| 1637727750 | |||
| 6e5f8f2a1d | |||
| 3ef1c34632 | |||
| 4187af38b2 | |||
| 19b3cae62e | |||
| a2358bbc83 | |||
| fbe09c26ae | |||
| 5b638a54a4 | |||
| d0d2ac545b | |||
| 51eef2b980 | |||
| 63cd037188 | |||
| d3e349c290 | |||
| bc16a6f723 | |||
| e480da69e9 | |||
| 1d466f86a0 | |||
| 9dfa5cf713 | |||
| bd8bdb8a98 | |||
| 302cfb116e | |||
| 695ea1717f | |||
| 1206c2b141 | |||
| 3539f06146 | |||
| 4a6e0a13cd | |||
| fc630ae6eb | |||
| a317a3d866 | |||
| 88118afb8f | |||
| 9ad7981e36 | |||
| 68b820ed09 | |||
| 53bcf0d16b | |||
| 438c783c7d | |||
| 41524880c6 | |||
| 2361dc131e | |||
| 44d32815b1 | |||
| 87c3335e01 | |||
| 76e9d91f24 | |||
| 77fe9e892a | |||
| eefbb4da64 | |||
| 8f65f88dc0 | |||
| a2793f31b4 | |||
| 64d8e6cc9b | |||
| 679a47a51d | |||
| d4678c8e04 | |||
| 43b132bec6 | |||
| 08fca57d12 | |||
| acabacb971 | |||
| 1a130fca3c | |||
| 067f79dde5 | |||
| 45758a5cec | |||
| 52d98ab7af | |||
| 0b680be97b | |||
| 7c28b15471 | |||
| abf3c866fb | |||
| 5a4ada04ac | |||
| c08329c0c5 | |||
| a856baa6a8 | |||
| 611786e4b5 | |||
| ac63cf4fa5 | |||
| f6bb55effb | |||
| 6020ab8e65 | |||
| 3076367168 | |||
| 721b22d87a | |||
| 85b756cb74 | |||
| 0ce76d2c5d | |||
| 66cf02c6b0 | |||
| 7441ce7f16 | |||
| 9dbcd8cf00 | |||
| e6db4418b0 | |||
| 835d6c1fbd | |||
| 9fb3e14989 | |||
| 2c90edd7b7 | |||
| 95b2cdf7f4 | |||
| f0e71a8bc4 | |||
| 3ecf84855e | |||
| 2848b95fe0 | |||
| 0039bc0cf0 | |||
| 671a53e850 | |||
| 057e5181ea | |||
| 178ca56aaf | |||
| 164fbaf007 | |||
| 61ccf14953 | |||
| 65cf2586c5 | |||
| 6e683f2286 | |||
| bae4cdd765 | |||
| a7c3e842d6 | |||
| b6e24db68c | |||
| 7dea8b8ca2 | |||
| aeb5fc1fb0 | |||
| 4542f58be7 | |||
| 62f33d3fcf | |||
| 956561e143 | |||
| 9fed1ac8c3 | |||
| 9dbe3bdcc0 | |||
| d547ae0181 | |||
| b8b1278e1f | |||
| 381047e386 | |||
| fbbbd46bee | |||
| 8abffbd0df | |||
| 376b40a735 | |||
| 89fa1cbdd2 | |||
| 0d75e6d10c | |||
| 01758c4c59 | |||
| f37833a59c | |||
| 52e6c4c4be | |||
| 874dce4407 | |||
| f21e8af830 | |||
| 8aae3490da | |||
| 9bd793ffe6 | |||
| 96ceb535f4 | |||
| 0c54a55ae8 |
+18
-105
@@ -1,10 +1,12 @@
|
||||
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: /
|
||||
@@ -15,6 +17,7 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -31,28 +34,8 @@ updates:
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- 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: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'type: dependency-upgrade'
|
||||
- 'in: build'
|
||||
|
||||
# 7.0.x
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 7.0.x
|
||||
target-branch: 6.4.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
@@ -61,10 +44,10 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
- dependency-name: io.spring.nullability:*
|
||||
- dependency-name: org.python:jython
|
||||
- dependency-name: org.apache.directory.server:*
|
||||
- dependency-name: org.apache.directory.shared:*
|
||||
@@ -74,34 +57,11 @@ updates:
|
||||
- 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
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: npm
|
||||
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: /
|
||||
@@ -112,6 +72,7 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -131,6 +92,17 @@ updates:
|
||||
- dependency-name: '*'
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
|
||||
- package-ecosystem: npm
|
||||
target-branch: docs-build
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'in: build'
|
||||
|
||||
- package-ecosystem: npm
|
||||
target-branch: main
|
||||
directory: /docs
|
||||
@@ -138,63 +110,4 @@ 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'
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
name: Merge Dependabot PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- '*.x'
|
||||
|
||||
run-name: Merge Dependabot PR ${{ github.ref_name }}
|
||||
|
||||
jobs:
|
||||
merge-dependabot-pr:
|
||||
permissions: write-all
|
||||
uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@v7
|
||||
with:
|
||||
mergeArguments: --auto --rebase
|
||||
@@ -14,12 +14,14 @@ permissions:
|
||||
jobs:
|
||||
snapshot-test:
|
||||
name: Test Against Snapshots
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@ed473b4dafba053c63a453d2d88a89df3b3e18b3 # v1
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- java-version: 25
|
||||
toolchain: 25
|
||||
- java-version: 21-ea
|
||||
toolchain: 21
|
||||
- java-version: 17
|
||||
toolchain: 17
|
||||
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
|
||||
@@ -31,6 +33,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Notification
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@ed473b4dafba053c63a453d2d88a89df3b3e18b3 # v1
|
||||
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@1
|
||||
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@e415dadd0910c901e7a7fabd67bbb355b2324500 # 1
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
jdk: [ 25 ]
|
||||
jdk: [ 17 ]
|
||||
with:
|
||||
runs-on: ${{ matrix.os }}
|
||||
java-version: ${{ matrix.jdk }}
|
||||
@@ -34,7 +34,6 @@ jobs:
|
||||
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
|
||||
@@ -42,7 +41,6 @@ jobs:
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
||||
with:
|
||||
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
java-version: 25
|
||||
secrets: inherit
|
||||
perform-release:
|
||||
name: Perform Release
|
||||
@@ -55,7 +53,6 @@ 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
|
||||
|
||||
@@ -18,21 +18,21 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Compute Version
|
||||
id: compute-version
|
||||
uses: spring-io/spring-release-actions/compute-version@0.0.3
|
||||
uses: spring-io/spring-release-actions/compute-version@2420148725bebe44bd59a575a9b1961ca4459b0b # 0.0.4
|
||||
- name: Get Today's Release Version
|
||||
id: todays-release
|
||||
uses: spring-io/spring-release-actions/get-todays-release-version@0.0.3
|
||||
uses: spring-io/spring-release-actions/get-todays-release-version@2420148725bebe44bd59a575a9b1961ca4459b0b # 0.0.4
|
||||
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@0.0.3
|
||||
uses: spring-io/spring-release-actions/compute-next-version@2420148725bebe44bd59a575a9b1961ca4459b0b # 0.0.4
|
||||
with:
|
||||
version: ${{ steps.todays-release.outputs.release-version }}
|
||||
- name: Schedule Next Milestone
|
||||
uses: spring-io/spring-release-actions/schedule-milestone@0.0.3
|
||||
uses: spring-io/spring-release-actions/schedule-milestone@2420148725bebe44bd59a575a9b1961ca4459b0b # 0.0.4
|
||||
with:
|
||||
version: ${{ steps.next-version.outputs.version }}
|
||||
version-date: ${{ steps.next-version.outputs.version-date }}
|
||||
|
||||
@@ -16,7 +16,7 @@ permissions:
|
||||
jobs:
|
||||
perform-release:
|
||||
name: Perform Release
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@ed473b4dafba053c63a453d2d88a89df3b3e18b3 # v1
|
||||
with:
|
||||
should-perform-release: true
|
||||
project-version: ${{ inputs.version }}
|
||||
|
||||
@@ -9,7 +9,6 @@ permissions:
|
||||
jobs:
|
||||
upgrade_wrapper:
|
||||
name: Execution
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Git configuration
|
||||
@@ -21,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 25
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
java-version: '25'
|
||||
java-version: '17'
|
||||
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@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -13,9 +13,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5
|
||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
||||
with:
|
||||
java-version: '25'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan
|
||||
@@ -26,15 +26,15 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5
|
||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
||||
with:
|
||||
java-version: '25'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Run Antora
|
||||
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
|
||||
- name: Upload Docs
|
||||
id: upload
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
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@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# List of active maintenance branches.
|
||||
branch: [ main, 7.0.x, 6.5.x, 6.4.x, 6.3.x ]
|
||||
branch: [ main, 6.5.x, 6.4.x, 6.3.x ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -12,25 +12,23 @@ permissions:
|
||||
|
||||
jobs:
|
||||
update-antora-ui-spring:
|
||||
name: Update on Supported Branches
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
name: Update on Supported Branches
|
||||
strategy:
|
||||
matrix:
|
||||
branch: [ '6.5.x', '7.0.x', 'main' ]
|
||||
branch: [ '6.4.x', '6.5.x', 'main' ]
|
||||
steps:
|
||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf
|
||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
|
||||
name: Update
|
||||
with:
|
||||
docs-branch: ${{ matrix.branch }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
antora-file-path: 'docs/antora-playbook.yml'
|
||||
update-antora-ui-spring-docs-build:
|
||||
name: Update on docs-build
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
name: Update on docs-build
|
||||
steps:
|
||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf
|
||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
|
||||
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@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
||||
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@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
||||
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=25-librca
|
||||
java=17.0.3-tem
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"java.gradle.buildServer.enabled": "off"
|
||||
"java.import.gradle.enabled": false
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ If you have a question, check Stack Overflow using
|
||||
https://stackoverflow.com/questions/tagged/spring-security+or+spring-ldap+or+spring-authorization-server+or+spring-session?tab=Newest[this list of tags].
|
||||
Find an existing discussion, or start a new one if necessary.
|
||||
|
||||
If you believe there is an issue, search through https://github.com/spring-projects/spring-security/issues[existing issues] trying a few different ways to find discussions, past or current, that are related to the issue.
|
||||
If you believe there is an issue, search through https://github.com/spring-projects/spring-security/issues[existing issues] trying a few different ways to find discussions, past or current, that are related to the issue.
|
||||
Reading those discussions helps you to learn about the issue, and helps us to make a decision.
|
||||
|
||||
[[find-an-issue]]
|
||||
@@ -94,7 +94,7 @@ Don't worry if you don't get them all correct the first time, we will help you.
|
||||
|
||||
1. [[sign-cla]] All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin.
|
||||
For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring].
|
||||
2. [[create-an-issue-list]] Must you https://github.com/spring-projects/spring-security/issues/new/choose[create an issue] first? No, but it is recommended for features and larger bug fixes. It's easier to discuss with the team first to determine the right fix or enhancement.
|
||||
2. [[create-an-issue-list]] Must you https://github.com/spring-projects/spring-security/issues/new/choose[create an issue] first? No, but it is recommended for features and larger bug fixes. It's easier discuss with the team first to determine the right fix or enhancement.
|
||||
For typos and straightforward bug fixes, starting with a pull request is encouraged.
|
||||
Please include a description for context and motivation.
|
||||
Note that the team may close your pull request if it's not a fit for the project.
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
plugins {
|
||||
id 'compile-warnings-error'
|
||||
id 'javadoc-warnings-error'
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
|
||||
+1
-2
@@ -31,7 +31,6 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Sources method security metadata from major JSR 250 security annotations.
|
||||
@@ -109,7 +108,7 @@ public class Jsr250MethodSecurityMetadataSource extends AbstractFallbackMethodSe
|
||||
if (role == null) {
|
||||
return role;
|
||||
}
|
||||
if (!StringUtils.hasLength(this.defaultRolePrefix)) {
|
||||
if (this.defaultRolePrefix == null || this.defaultRolePrefix.length() == 0) {
|
||||
return role;
|
||||
}
|
||||
if (role.startsWith(this.defaultRolePrefix)) {
|
||||
|
||||
+1
-3
@@ -53,9 +53,7 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @deprecated Use
|
||||
* <code>org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity</code>
|
||||
* or publish interceptors directly
|
||||
* @deprecated Use {@link EnableMethodSecurity} or publish interceptors directly
|
||||
*/
|
||||
@NullUnmarked
|
||||
@Deprecated
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ import org.springframework.security.web.FilterInvocation;
|
||||
*/
|
||||
@Deprecated
|
||||
@NullUnmarked
|
||||
@SuppressWarnings("serial")
|
||||
class WebExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<FilterInvocation> {
|
||||
|
||||
private final Expression authorizeExpression;
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
plugins {
|
||||
id 'compile-warnings-error'
|
||||
id 'javadoc-warnings-error'
|
||||
id 'security-nullability'
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.Locale;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
@@ -45,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
|
||||
* <code> org.springframework.security.acls.AclEntryVoter AclEntryVoter </code>
|
||||
* {@link org.springframework.security.acls.AclEntryVoter AclEntryVoter}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
@@ -74,7 +73,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
* be overridden using a null check in the expression itself).
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, @Nullable Object domainObject, Object permission) {
|
||||
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
|
||||
if (domainObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.aot.hint;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for ACL (Access Control List) classes.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
class AclRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
registerAclDomainHints(hints);
|
||||
registerJdbcSchemaHints(hints);
|
||||
}
|
||||
|
||||
private void registerAclDomainHints(RuntimeHints hints) {
|
||||
// Register core ACL domain types
|
||||
Stream
|
||||
.of(Acl.class, AccessControlEntry.class, AuditableAccessControlEntry.class, ObjectIdentity.class, Sid.class,
|
||||
AclImpl.class, AccessControlEntry.class, AuditLogger.class, ObjectIdentityImpl.class,
|
||||
PrincipalSid.class, GrantedAuthoritySid.class, BasePermission.class)
|
||||
.forEach((c) -> hints.reflection()
|
||||
.registerType(TypeReference.of(c),
|
||||
(builder) -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.ACCESS_DECLARED_FIELDS)));
|
||||
|
||||
}
|
||||
|
||||
private void registerJdbcSchemaHints(RuntimeHints hints) {
|
||||
String[] sqlFiles = new String[] { "createAclSchema.sql", "createAclSchemaMySQL.sql",
|
||||
"createAclSchemaOracle.sql", "createAclSchemaPostgres.sql", "createAclSchemaSqlServer.sql",
|
||||
"createAclSchemaWithAclClassIdType.sql", "select.sql" };
|
||||
for (String sqlFile : sqlFiles) {
|
||||
Resource sqlResource = new ClassPathResource(sqlFile);
|
||||
if (sqlResource.exists()) {
|
||||
hints.resources().registerResource(sqlResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AOT and native image hint support for ACLs.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls.aot.hint;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
+3
-5
@@ -18,8 +18,6 @@ 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;
|
||||
@@ -38,7 +36,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
|
||||
private Permission permission;
|
||||
|
||||
private final @Nullable Serializable id;
|
||||
private final Serializable id;
|
||||
|
||||
private final Sid sid;
|
||||
|
||||
@@ -48,7 +46,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
|
||||
private final boolean granting;
|
||||
|
||||
public AccessControlEntryImpl(@Nullable Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||
boolean auditSuccess, boolean auditFailure) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
@@ -135,7 +133,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Serializable getId() {
|
||||
public Serializable getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -99,8 +99,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Authentication authentication = context.getAuthentication();
|
||||
// Check if authorized by virtue of ACL ownership
|
||||
Sid currentUser = createCurrentUser(authentication);
|
||||
Sid owner = acl.getOwner();
|
||||
if (owner != null && currentUser.equals(owner)
|
||||
if (currentUser.equals(acl.getOwner())
|
||||
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
||||
return;
|
||||
}
|
||||
@@ -109,8 +108,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy
|
||||
.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities);
|
||||
if (owner instanceof GrantedAuthoritySid
|
||||
&& authorities.contains(((GrantedAuthoritySid) owner).getGrantedAuthority())) {
|
||||
if (acl.getOwner() instanceof GrantedAuthoritySid
|
||||
&& authorities.contains(((GrantedAuthoritySid) acl.getOwner()).getGrantedAuthority())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@ 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;
|
||||
@@ -43,7 +41,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
private @Nullable Acl parentAcl;
|
||||
private Acl parentAcl;
|
||||
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
@@ -56,10 +54,10 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
private Serializable id;
|
||||
|
||||
// OwnershipAcl
|
||||
private @Nullable Sid owner;
|
||||
private Sid owner;
|
||||
|
||||
// includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||
private @Nullable List<Sid> loadedSids = null;
|
||||
private List<Sid> loadedSids = null;
|
||||
|
||||
private boolean entriesInheriting = true;
|
||||
|
||||
@@ -99,8 +97,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* @param owner the owner (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
PermissionGrantingStrategy grantingStrategy, @Nullable Acl parentAcl, @Nullable List<Sid> loadedSids,
|
||||
boolean entriesInheriting, Sid owner) {
|
||||
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting,
|
||||
Sid owner) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
@@ -119,7 +117,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", "NullAway.Init" })
|
||||
@SuppressWarnings("unused")
|
||||
private AclImpl() {
|
||||
}
|
||||
|
||||
@@ -201,7 +199,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSidLoaded(@Nullable List<Sid> sids) {
|
||||
public boolean isSidLoaded(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()) {
|
||||
@@ -240,19 +238,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Sid getOwner() {
|
||||
public Sid getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(@Nullable Acl newParent) {
|
||||
public void setParent(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 @Nullable Acl getParentAcl() {
|
||||
public Acl getParentAcl() {
|
||||
return this.parentAcl;
|
||||
}
|
||||
|
||||
|
||||
+4
-10
@@ -18,8 +18,6 @@ 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;
|
||||
@@ -80,13 +78,13 @@ public class SpringCacheBasedAclCache implements AclCache {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
return getFromCache((Object) objectIdentity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable MutableAcl getFromCache(Serializable pk) {
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
return getFromCache((Object) pk);
|
||||
}
|
||||
@@ -103,16 +101,12 @@ public class SpringCacheBasedAclCache implements AclCache {
|
||||
this.cache.put(acl.getId(), acl);
|
||||
}
|
||||
|
||||
private @Nullable MutableAcl getFromCache(Object key) {
|
||||
private MutableAcl getFromCache(Object key) {
|
||||
Cache.ValueWrapper element = this.cache.get(key);
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
Object value = element.get();
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return initializeTransientFields((MutableAcl) value);
|
||||
return initializeTransientFields((MutableAcl) element.get());
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
|
||||
@@ -17,7 +17,4 @@
|
||||
/**
|
||||
* Basic implementation of access control lists (ACLs) interfaces.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -23,7 +23,6 @@ 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;
|
||||
@@ -68,10 +67,10 @@ class AclClassIdUtils {
|
||||
* @return The identifier in the appropriate target Java type. Typically Long or UUID.
|
||||
* @throws SQLException
|
||||
*/
|
||||
@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);
|
||||
Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
|
||||
if (isString(identifier) && hasValidClassIdType(resultSet)
|
||||
&& canConvertFromStringTo(classIdTypeFrom(resultSet))) {
|
||||
return convertFromStringTo((String) identifier, classIdTypeFrom(resultSet));
|
||||
}
|
||||
// Assume it should be a Long type
|
||||
return convertToLong(identifier);
|
||||
@@ -87,38 +86,28 @@ class AclClassIdUtils {
|
||||
}
|
||||
}
|
||||
|
||||
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(ResultSet resultSet) throws SQLException {
|
||||
return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
|
||||
}
|
||||
|
||||
private @Nullable Class<? extends Serializable> classIdTypeFrom(String className) {
|
||||
private <T extends Serializable> Class<T> classIdTypeFrom(String className) {
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Class.forName(className).asSubclass(Serializable.class);
|
||||
return (Class) Class.forName(className);
|
||||
}
|
||||
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> @Nullable T convertFromStringTo(String identifier, Class<T> targetType) {
|
||||
private <T extends Serializable> T convertFromStringTo(String identifier, Class<T> targetType) {
|
||||
return this.conversionService.convert(identifier, targetType);
|
||||
}
|
||||
|
||||
@@ -132,7 +121,7 @@ class AclClassIdUtils {
|
||||
* exception occurred
|
||||
* @throws IllegalArgumentException if targetType is null
|
||||
*/
|
||||
private @Nullable Long convertToLong(Serializable identifier) {
|
||||
private Long convertToLong(Serializable identifier) {
|
||||
if (this.conversionService.canConvert(identifier.getClass(), Long.class)) {
|
||||
return this.conversionService.convert(identifier, Long.class);
|
||||
}
|
||||
@@ -151,10 +140,10 @@ class AclClassIdUtils {
|
||||
private static class StringToLongConverter implements Converter<String, Long> {
|
||||
|
||||
@Override
|
||||
public Long convert(@Nullable String identifierAsString) {
|
||||
public Long convert(String identifierAsString) {
|
||||
if (identifierAsString == null) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(Long.class), identifierAsString, new NullPointerException());
|
||||
TypeDescriptor.valueOf(Long.class), null, null);
|
||||
|
||||
}
|
||||
return Long.parseLong(identifierAsString);
|
||||
@@ -165,10 +154,10 @@ class AclClassIdUtils {
|
||||
private static class StringToUUIDConverter implements Converter<String, UUID> {
|
||||
|
||||
@Override
|
||||
public UUID convert(@Nullable String identifierAsString) {
|
||||
public UUID convert(String identifierAsString) {
|
||||
if (identifierAsString == null) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(UUID.class), identifierAsString, new NullPointerException());
|
||||
TypeDescriptor.valueOf(UUID.class), null, null);
|
||||
|
||||
}
|
||||
return UUID.fromString(identifierAsString);
|
||||
|
||||
@@ -31,8 +31,6 @@ 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;
|
||||
@@ -226,8 +224,7 @@ 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 @Nullable List<Sid> sids) {
|
||||
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow, final List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
String sql = computeRepeatingSql(this.lookupPrimaryKeysWhereClause, findNow.size());
|
||||
@@ -267,7 +264,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* automatically create entries if required)
|
||||
*/
|
||||
@Override
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids) {
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||
Assert.isTrue(this.batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
// Map<ObjectIdentity,Acl>
|
||||
@@ -326,7 +323,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* properly-configured parent ACLs.
|
||||
*/
|
||||
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities,
|
||||
@Nullable List<Sid> sids) {
|
||||
List<Sid> sids) {
|
||||
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
||||
|
||||
// contains Acls with StubAclParents
|
||||
@@ -402,10 +399,8 @@ 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(), owner);
|
||||
this.grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
|
||||
@@ -511,9 +506,9 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
private final Map<Serializable, Acl> acls;
|
||||
|
||||
private final @Nullable List<Sid> sids;
|
||||
private final List<Sid> sids;
|
||||
|
||||
ProcessResultSet(Map<Serializable, Acl> acls, @Nullable List<Sid> sids) {
|
||||
ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs cannot be null");
|
||||
this.acls = acls;
|
||||
this.sids = sids; // can be null
|
||||
@@ -584,9 +579,6 @@ 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"));
|
||||
|
||||
@@ -678,7 +670,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSidLoaded(@Nullable List<Sid> sids) {
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ 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;
|
||||
@@ -99,7 +98,7 @@ public class JdbcAclService implements AclService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
public 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);
|
||||
@@ -110,14 +109,11 @@ 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, @Nullable List<Sid> sids) throws NotFoundException {
|
||||
public Acl readAclById(ObjectIdentity object, 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);
|
||||
@@ -135,7 +131,7 @@ public class JdbcAclService implements AclService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids)
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
|
||||
throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
|
||||
// Check every requested object identity was found (throw NotFoundException if
|
||||
|
||||
+15
-40
@@ -22,8 +22,6 @@ 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;
|
||||
@@ -122,7 +120,6 @@ 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
|
||||
@@ -158,12 +155,9 @@ 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);
|
||||
Long sidPrimaryKey = createOrRetrieveSidPrimaryKey(entry.getSid(), true);
|
||||
Assert.state(sidPrimaryKey != null, "SID primary key cannot be null");
|
||||
stmt.setLong(3, sidPrimaryKey);
|
||||
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true));
|
||||
stmt.setInt(4, entry.getPermission().getMask());
|
||||
stmt.setBoolean(5, entry.isGranting());
|
||||
stmt.setBoolean(6, entry.isAuditSuccess());
|
||||
@@ -195,14 +189,11 @@ 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 @Nullable Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||
List<@Nullable Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
|
||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
|
||||
|
||||
if (!classIds.isEmpty()) {
|
||||
Long result = classIds.get(0);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return classIds.get(0);
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
@@ -213,9 +204,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName());
|
||||
}
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
Long result = this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
|
||||
Assert.state(result != null, "Failed to retrieve class primary key");
|
||||
return result;
|
||||
return this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -230,7 +219,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized
|
||||
* implementation.
|
||||
*/
|
||||
protected @Nullable Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (sid instanceof PrincipalSid) {
|
||||
String sidName = ((PrincipalSid) sid).getPrincipal();
|
||||
@@ -251,22 +240,16 @@ 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 @Nullable Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal,
|
||||
boolean allowCreate) {
|
||||
List<@Nullable Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class,
|
||||
sidIsPrincipal, sidName);
|
||||
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
|
||||
List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidIsPrincipal,
|
||||
sidName);
|
||||
if (!sidIds.isEmpty()) {
|
||||
Long result = sidIds.get(0);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return sidIds.get(0);
|
||||
}
|
||||
if (allowCreate) {
|
||||
this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
Long result = this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
|
||||
Assert.state(result != null, "Failed to retrieve sid primary key");
|
||||
return result;
|
||||
return this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -296,9 +279,6 @@ 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);
|
||||
@@ -339,11 +319,10 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param oid to find
|
||||
* @return the object identity or null if not found
|
||||
*/
|
||||
protected @Nullable Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
Long result = this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class,
|
||||
oid.getType(), oid.getIdentifier().toString());
|
||||
return result;
|
||||
return this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, oid.getType(),
|
||||
oid.getIdentifier().toString());
|
||||
}
|
||||
catch (DataAccessException notFound) {
|
||||
return null;
|
||||
@@ -361,11 +340,7 @@ 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
|
||||
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity());
|
||||
if (oidPrimaryKey == null) {
|
||||
throw new NotFoundException("Object identity not found for ACL: " + acl.getObjectIdentity());
|
||||
}
|
||||
deleteEntries(oidPrimaryKey);
|
||||
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
|
||||
|
||||
// Create this ACL's ACEs in the acl_entry table
|
||||
createEntries(acl);
|
||||
|
||||
@@ -19,8 +19,6 @@ 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;
|
||||
@@ -44,6 +42,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, @Nullable List<Sid> sids);
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,4 @@
|
||||
/**
|
||||
* JDBC-based persistence of ACL information
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an individual permission assignment within an {@link Acl}.
|
||||
*
|
||||
@@ -38,7 +36,7 @@ public interface AccessControlEntry extends Serializable {
|
||||
* Obtains an identifier that represents this ACE.
|
||||
* @return the identifier, or <code>null</code> if unsaved
|
||||
*/
|
||||
@Nullable Serializable getId();
|
||||
Serializable getId();
|
||||
|
||||
Permission getPermission();
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ 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.
|
||||
*
|
||||
@@ -84,7 +82,7 @@ public interface Acl extends Serializable {
|
||||
* @return the owner (may be <tt>null</tt> if the implementation does not use
|
||||
* ownership concepts)
|
||||
*/
|
||||
@Nullable Sid getOwner();
|
||||
Sid getOwner();
|
||||
|
||||
/**
|
||||
* A domain object may have a parent for the purpose of ACL inheritance. If there is a
|
||||
@@ -105,7 +103,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)
|
||||
*/
|
||||
@Nullable Acl getParentAcl();
|
||||
Acl getParentAcl();
|
||||
|
||||
/**
|
||||
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down
|
||||
@@ -191,6 +189,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(@Nullable List<Sid> sids);
|
||||
boolean isSidLoaded(List<Sid> sids);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.acls.jdbc.JdbcAclService;
|
||||
|
||||
/**
|
||||
@@ -33,9 +31,9 @@ public interface AclCache {
|
||||
|
||||
void evictFromCache(ObjectIdentity objectIdentity);
|
||||
|
||||
@Nullable MutableAcl getFromCache(ObjectIdentity objectIdentity);
|
||||
MutableAcl getFromCache(ObjectIdentity objectIdentity);
|
||||
|
||||
@Nullable MutableAcl getFromCache(Serializable pk);
|
||||
MutableAcl getFromCache(Serializable pk);
|
||||
|
||||
void putInCache(MutableAcl acl);
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ 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.
|
||||
*
|
||||
@@ -34,7 +32,7 @@ public interface AclService {
|
||||
* @param parentIdentity to locate children of
|
||||
* @return the children (or <tt>null</tt> if none were found)
|
||||
*/
|
||||
@Nullable List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(List)} except it returns only a single Acl.
|
||||
@@ -61,7 +59,7 @@ public interface AclService {
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object, @Nullable List<Sid> sids) throws NotFoundException;
|
||||
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.
|
||||
@@ -100,7 +98,6 @@ public interface AclService {
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids)
|
||||
throws NotFoundException;
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,4 @@
|
||||
* 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,7 +24,4 @@
|
||||
* 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;
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||
org.springframework.security.acls.aot.hint.AclRuntimeHints
|
||||
@@ -478,7 +478,6 @@ public class AclImplTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hashCodeWithoutStackOverFlow() throws Exception {
|
||||
Sid sid = new PrincipalSid("pSid");
|
||||
ObjectIdentity oid = new ObjectIdentityImpl("type", 1);
|
||||
|
||||
@@ -29,7 +29,6 @@ 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;
|
||||
|
||||
@@ -47,6 +46,7 @@ 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,8 +109,7 @@ 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(), ArgumentMatchers.<RowMapper<ObjectIdentity>>any(), eq(args)))
|
||||
.willReturn(result);
|
||||
given(this.jdbcOperations.query(anyString(), any(RowMapper.class), eq(args))).willReturn(result);
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L);
|
||||
List<ObjectIdentity> objectIdentities = this.aclService.findChildren(objectIdentity);
|
||||
assertThat(objectIdentities).hasSize(1);
|
||||
|
||||
+4
-2
@@ -80,10 +80,11 @@ 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"),
|
||||
@@ -115,10 +116,11 @@ 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,17 +1,13 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'io.freefair.aspectj'
|
||||
apply plugin: 'javadoc-warnings-error'
|
||||
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,7 +1,6 @@
|
||||
import io.spring.gradle.convention.SpringModulePlugin
|
||||
|
||||
apply plugin: 'io.spring.convention.bom'
|
||||
apply plugin: 'compile-warnings-error'
|
||||
|
||||
dependencies {
|
||||
constraints {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import io.spring.gradle.IncludeRepoTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import trang.RncToXsd
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
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.14'
|
||||
toolVersion = '0.8.9'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ def toolchainVersion() {
|
||||
if (project.hasProperty('testToolchain')) {
|
||||
return project.property('testToolchain').toString().toInteger()
|
||||
}
|
||||
return 25
|
||||
return 17
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
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')
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
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,7 +1,5 @@
|
||||
plugins {
|
||||
id 'security-nullability'
|
||||
id 'javadoc-warnings-error'
|
||||
id 'compile-warnings-error'
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ 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;
|
||||
@@ -165,6 +166,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
|
||||
* @param authentication
|
||||
* @return
|
||||
*/
|
||||
@NullUnmarked
|
||||
private @Nullable String getServiceUrl(Authentication authentication) {
|
||||
String serviceUrl;
|
||||
if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.security.jackson.SecurityJacksonModules;
|
||||
* @since 7.0
|
||||
* @see SecurityJacksonModules
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CasJacksonModule extends SecurityJacksonModule {
|
||||
|
||||
public CasJacksonModule() {
|
||||
|
||||
@@ -17,7 +17,4 @@
|
||||
/**
|
||||
* Jackson 3+ serialization support for CAS.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.cas.jackson;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+1
-2
@@ -91,8 +91,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
|
||||
*/
|
||||
protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) {
|
||||
return WebUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null,
|
||||
this.serviceProperties.getServiceParameter(), this.serviceProperties.getArtifactParameter(),
|
||||
this.encodeServiceUrlWithSessionId);
|
||||
this.serviceProperties.getArtifactParameter(), this.encodeServiceUrlWithSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-11
@@ -34,7 +34,6 @@ import org.springframework.util.Assert;
|
||||
* and using the current URL minus the artifact and the corresponding value.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Ngoc Nhan
|
||||
*/
|
||||
final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
implements ServiceAuthenticationDetails {
|
||||
@@ -75,9 +74,10 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails that)) {
|
||||
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) {
|
||||
return false;
|
||||
}
|
||||
ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj;
|
||||
return this.serviceUrl.equals(that.getServiceUrl());
|
||||
}
|
||||
|
||||
@@ -101,11 +101,7 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
/**
|
||||
* If present, removes the artifactParameterName and the corresponding value from the
|
||||
* query String.
|
||||
* @param request the current {@link HttpServletRequest} to obtain the
|
||||
* {@link #getServiceUrl()} from.
|
||||
* @param artifactPattern the {@link Pattern} that will be used to clean up the query
|
||||
* string from containing the artifact name and value. This can be created using
|
||||
* {@link #createArtifactPattern(String)}.
|
||||
* @param request
|
||||
* @return the query String minus the artifactParameterName and the corresponding
|
||||
* value.
|
||||
*/
|
||||
@@ -115,7 +111,7 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
return null;
|
||||
}
|
||||
String result = artifactPattern.matcher(query).replaceFirst("");
|
||||
if (result.isEmpty()) {
|
||||
if (result.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
// strip off the trailing & only if the artifact was the first query param
|
||||
@@ -126,9 +122,8 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
* Creates a {@link Pattern} that can be passed into the constructor. This allows the
|
||||
* {@link Pattern} to be reused for every instance of
|
||||
* {@link DefaultServiceAuthenticationDetails}.
|
||||
* @param artifactParameterName the artifactParameterName that is removed from the
|
||||
* current URL. The result becomes the service url. Cannot be null or an empty String.
|
||||
* @return a {@link Pattern}
|
||||
* @param artifactParameterName
|
||||
* @return
|
||||
*/
|
||||
static Pattern createArtifactPattern(String artifactParameterName) {
|
||||
Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length");
|
||||
|
||||
@@ -4,9 +4,6 @@ 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: 'compile-warnings-error'
|
||||
apply plugin: 'javadoc-warnings-error'
|
||||
|
||||
configurations {
|
||||
opensaml5 {
|
||||
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.ldap;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathAware;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
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.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class Ldap247ITests {
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private LdapGroupDao ldapGroupDao;
|
||||
|
||||
@Test
|
||||
public void verifyThatBasePathIsProperlyPopulated() {
|
||||
this.spring.register(FromContextSourceConfig.class).autowire();
|
||||
assertThat(this.ldapGroupDao).isNotNull();
|
||||
assertThat(this.ldapGroupDao.getBasePath()).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableMethodSecurity
|
||||
@Import(BaseLdapServerConfig.class)
|
||||
static class FromContextSourceConfig {
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
|
||||
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
|
||||
factory.setUserDnPatterns("uid={0},ou=people");
|
||||
return factory.createAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
static MethodSecurityExpressionHandler securityExpressionHandler(LdapGroupDao ldap) {
|
||||
return new MethodSecurityExpressionHandler(ldap);
|
||||
}
|
||||
|
||||
@Bean
|
||||
static LdapGroupDao ldapGroupDao() {
|
||||
return new LdapGroupDao();
|
||||
}
|
||||
|
||||
@Bean
|
||||
static BaseLdapPathBeanPostProcessor baseLdapPathBeanPostProcessor() {
|
||||
return new BaseLdapPathBeanPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
UnboundIdContainer ldapServer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||
int port = container.getPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.container.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
|
||||
|
||||
private final LdapGroupDao groupDao;
|
||||
|
||||
MethodSecurityExpressionHandler(LdapGroupDao groupDao) {
|
||||
this.groupDao = groupDao;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class LdapGroupDao implements BaseLdapPathAware {
|
||||
|
||||
private Name basePath;
|
||||
|
||||
LdapGroupDao() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseLdapPath(DistinguishedName baseLdapPath) {
|
||||
this.basePath = baseLdapPath;
|
||||
}
|
||||
|
||||
Name getBasePath() {
|
||||
return this.basePath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-3
@@ -20,7 +20,6 @@ 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;
|
||||
|
||||
@@ -99,14 +98,12 @@ 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.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd",
|
||||
.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",
|
||||
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\\.1.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-7\\.0.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
-2
@@ -36,7 +36,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
@@ -303,7 +302,6 @@ public class AuthenticationConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Contract("!null -> !null; null -> null")
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return getPasswordEncoder().encode(rawPassword);
|
||||
}
|
||||
|
||||
+6
-4
@@ -1881,7 +1881,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #securityMatchers(Customizer)} will not override previous
|
||||
* invocations of {@link #securityMatchers(Customizer)}
|
||||
* invocations of {@link #securityMatchers()}}, {@link #securityMatchers(Customizer)}
|
||||
* {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)}
|
||||
* </p>
|
||||
*
|
||||
@@ -2004,7 +2004,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* <p>
|
||||
* Invoking {@link #securityMatcher(RequestMatcher)} will override previous
|
||||
* invocations of {@link #securityMatcher(RequestMatcher)},
|
||||
* {@link #securityMatcher(String...)} and {@link #securityMatchers(Customizer)}
|
||||
* {@link #securityMatcher(String...)}, {@link #securityMatchers(Customizer)} and
|
||||
* {@link #securityMatchers()}
|
||||
* </p>
|
||||
* @param requestMatcher the {@link RequestMatcher} to use, for example,
|
||||
* {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")}
|
||||
@@ -2023,8 +2024,9 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link #securityMatcher(String...)} will override previous invocations of
|
||||
* {@link #securityMatcher(String...)}, {@link #securityMatcher(RequestMatcher)} and
|
||||
* {@link #securityMatchers(Customizer)}.
|
||||
* {@link #securityMatcher(String...)} (String)}},
|
||||
* {@link #securityMatcher(RequestMatcher)} ()}, {@link #securityMatchers(Customizer)}
|
||||
* (String)} and {@link #securityMatchers()} (String)}.
|
||||
* </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(ObjectProvider)}
|
||||
* {@link WebSecurityConfiguration#springSecurityFilterChain()}
|
||||
* </p>
|
||||
* @param securityFilterChainBuilder the builder to use to create the
|
||||
* {@link SecurityFilterChain} instances
|
||||
|
||||
+3
-3
@@ -30,7 +30,6 @@ import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
@@ -239,7 +238,9 @@ class HttpSecurityConfiguration {
|
||||
Map<Class<?>, Object> sharedObjects = new HashMap<>();
|
||||
sharedObjects.put(ApplicationContext.class, this.context);
|
||||
sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
|
||||
sharedObjects.put(PathPatternRequestMatcher.Builder.class, constructRequestMatcherBuilder(this.context));
|
||||
sharedObjects.put(PathPatternRequestMatcher.Builder.class,
|
||||
this.context.getBeanProvider(PathPatternRequestMatcher.Builder.class)
|
||||
.getIfUnique(() -> constructRequestMatcherBuilder(this.context)));
|
||||
return sharedObjects;
|
||||
}
|
||||
|
||||
@@ -294,7 +295,6 @@ class HttpSecurityConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Contract("!null -> !null; null -> null")
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return getPasswordEncoder().encode(rawPassword);
|
||||
}
|
||||
|
||||
+1
-2
@@ -39,7 +39,6 @@ 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>>
|
||||
@@ -159,7 +158,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
this.authenticationFilter.afterPropertiesSet();
|
||||
http.addFilter(postProcess(this.authenticationFilter));
|
||||
http.addFilter(this.authenticationFilter);
|
||||
}
|
||||
|
||||
private String getKey() {
|
||||
|
||||
+3
@@ -39,6 +39,7 @@ 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;
|
||||
@@ -180,6 +181,8 @@ 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) {
|
||||
|
||||
+3
-4
@@ -47,8 +47,8 @@ import org.springframework.util.Assert;
|
||||
* The following configuration options are available:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #authorizationCodeGrant(Customizer)} - support for the OAuth 2.0
|
||||
* Authorization Code Grant</li>
|
||||
* <li>{@link #authorizationCodeGrant()} - support for the OAuth 2.0 Authorization Code
|
||||
* Grant</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
@@ -59,8 +59,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* The following {@code Filter}'s are populated for
|
||||
* {@link #authorizationCodeGrant(Customizer)}:
|
||||
* The following {@code Filter}'s are populated for {@link #authorizationCodeGrant()}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link OAuth2AuthorizationRequestRedirectFilter}</li>
|
||||
|
||||
+4
-8
@@ -521,10 +521,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
public OpaqueTokenConfigurer introspectionUri(String introspectionUri) {
|
||||
Assert.notNull(introspectionUri, "introspectionUri cannot be null");
|
||||
this.introspectionUri = introspectionUri;
|
||||
this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri)
|
||||
.clientId(this.clientId)
|
||||
.clientSecret(this.clientSecret)
|
||||
.build();
|
||||
this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
|
||||
this.clientSecret);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -533,10 +531,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
Assert.notNull(clientSecret, "clientSecret cannot be null");
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri)
|
||||
.clientId(this.clientId)
|
||||
.clientSecret(this.clientSecret)
|
||||
.build();
|
||||
this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
|
||||
this.clientSecret);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -21,7 +21,6 @@ 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;
|
||||
@@ -43,8 +42,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <p>
|
||||
* Defaults are provided for all configuration options with the only required
|
||||
* configuration being a
|
||||
* {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository(HttpSecurityBuilder)}.
|
||||
* configuration being a {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository}.
|
||||
* Alternatively, a {@link RelyingPartyRegistrationRepository} {@code @Bean} may be
|
||||
* registered instead.
|
||||
*
|
||||
@@ -69,7 +67,7 @@ import org.springframework.util.Assert;
|
||||
* </ul>
|
||||
*
|
||||
* @since 6.1
|
||||
* @see HttpSecurity#saml2Metadata(Customizer)
|
||||
* @see HttpSecurity#saml2Metadata()
|
||||
* @see Saml2MetadataFilter
|
||||
* @see RelyingPartyRegistrationRepository
|
||||
*/
|
||||
|
||||
-4
@@ -124,10 +124,6 @@ class AuthorizationFilterParser implements BeanDefinitionParser {
|
||||
List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
for (Element interceptMessage : interceptMessages) {
|
||||
String accessExpression = interceptMessage.getAttribute(ATT_ACCESS);
|
||||
if (!StringUtils.hasText(accessExpression)) {
|
||||
parserContext.getReaderContext().error("access attribute cannot be empty or null", interceptMessage);
|
||||
continue;
|
||||
}
|
||||
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(WebExpressionAuthorizationManager.class);
|
||||
authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef);
|
||||
|
||||
+1
-2
@@ -142,11 +142,10 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
ManagedMap<BeanMetadataElement, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<>();
|
||||
for (Element urlElt : urlElts) {
|
||||
String access = urlElt.getAttribute(ATT_ACCESS);
|
||||
String path = urlElt.getAttribute(ATT_PATTERN);
|
||||
if (!StringUtils.hasText(access)) {
|
||||
parserContext.getReaderContext().error("access attribute cannot be empty or null", urlElt);
|
||||
continue;
|
||||
}
|
||||
String path = urlElt.getAttribute(ATT_PATTERN);
|
||||
String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF);
|
||||
boolean hasMatcherRef = StringUtils.hasText(matcherRef);
|
||||
if (!hasMatcherRef && !StringUtils.hasText(path)) {
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ public final class PathPatternRequestMatcherFactoryBean
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.basePath != null) {
|
||||
this.builder.basePath(this.basePath);
|
||||
this.builder = this.builder.basePath(this.basePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -2162,7 +2162,7 @@ public class ServerHttpSecurity {
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @since 5.6
|
||||
* @see #passwordManagement(Customizer)
|
||||
* @see #passwordManagement()
|
||||
*/
|
||||
public final class PasswordManagementSpec {
|
||||
|
||||
@@ -2663,7 +2663,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures cache control headers
|
||||
*
|
||||
* @see HeaderSpec#cache(Customizer)
|
||||
* @see #cache()
|
||||
*/
|
||||
public final class CacheSpec {
|
||||
|
||||
@@ -2684,7 +2684,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* The content type headers
|
||||
*
|
||||
* @see HeaderSpec#contentTypeOptions(Customizer)
|
||||
* @see #contentTypeOptions()
|
||||
*/
|
||||
public final class ContentTypeOptionsSpec {
|
||||
|
||||
@@ -2705,7 +2705,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures frame options response header
|
||||
*
|
||||
* @see HeaderSpec#frameOptions(Customizer)
|
||||
* @see #frameOptions()
|
||||
*/
|
||||
public final class FrameOptionsSpec {
|
||||
|
||||
@@ -2737,7 +2737,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures Strict Transport Security response header
|
||||
*
|
||||
* @see HeaderSpec#hsts(Customizer)
|
||||
* @see #hsts()
|
||||
*/
|
||||
public final class HstsSpec {
|
||||
|
||||
@@ -2796,7 +2796,7 @@ public class ServerHttpSecurity {
|
||||
/**
|
||||
* Configures x-xss-protection response header
|
||||
*
|
||||
* @see HeaderSpec#xssProtection(Customizer)
|
||||
* @see #xssProtection()
|
||||
*/
|
||||
public final class XssProtectionSpec {
|
||||
|
||||
@@ -2830,7 +2830,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Content-Security-Policy} response header.
|
||||
*
|
||||
* @since 5.1
|
||||
* @see HeaderSpec#contentSecurityPolicy(Customizer)
|
||||
* @see #contentSecurityPolicy(String)
|
||||
*/
|
||||
public final class ContentSecurityPolicySpec {
|
||||
|
||||
@@ -2884,7 +2884,8 @@ 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(String)} instead
|
||||
* @deprecated For removal in 7.0. Use {@link #featurePolicy(Customizer)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public HeaderSpec and() {
|
||||
@@ -2897,7 +2898,7 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Permissions-Policy} response header.
|
||||
*
|
||||
* @since 5.5
|
||||
* @see HeaderSpec#permissionsPolicy(Customizer)
|
||||
* @see #permissionsPolicy()
|
||||
*/
|
||||
public final class PermissionsPolicySpec {
|
||||
|
||||
@@ -2920,7 +2921,8 @@ public class ServerHttpSecurity {
|
||||
* Configures {@code Referrer-Policy} response header.
|
||||
*
|
||||
* @since 5.1
|
||||
* @see HeaderSpec#referrerPolicy(Customizer)
|
||||
* @see #referrerPolicy()
|
||||
* @see #referrerPolicy(ReferrerPolicy)
|
||||
*/
|
||||
public final class ReferrerPolicySpec {
|
||||
|
||||
|
||||
+42
-9
@@ -23,7 +23,9 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -42,18 +44,25 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.vote.ConsensusBased;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.http.MessageMatcherFactoryBean;
|
||||
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionAuthorizationManager;
|
||||
import org.springframework.security.messaging.access.expression.MessageAuthorizationContextSecurityExpressionHandler;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
|
||||
import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor;
|
||||
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
|
||||
@@ -66,6 +75,7 @@ import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatche
|
||||
import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
|
||||
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -209,15 +219,9 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
String messageType = interceptMessage.getAttribute(TYPE_ATTR);
|
||||
BeanDefinition matcher = createMatcher(matcherPattern, messageType, parserContext, interceptMessage);
|
||||
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MessageExpressionAuthorizationManager.class);
|
||||
.rootBeanDefinition(ExpressionBasedAuthorizationManager.class);
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
BeanDefinitionBuilder authorizationManagerBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MessageExpressionAuthorizationManager.class);
|
||||
authorizationManagerBuilder.setFactoryMethod("withSecurityExpressionHandler");
|
||||
authorizationManagerBuilder.addConstructorArgReference(expressionHandlerRef);
|
||||
String authorizationManagerBuilderRef = context
|
||||
.registerWithGeneratedName(authorizationManagerBuilder.getBeanDefinition());
|
||||
authorizationManager.setFactoryMethodOnBean("expression", authorizationManagerBuilderRef);
|
||||
authorizationManager.addConstructorArgReference(expressionHandlerRef);
|
||||
}
|
||||
authorizationManager.addConstructorArgValue(accessExpression);
|
||||
matcherToExpression.put(matcher, authorizationManager.getBeanDefinition());
|
||||
@@ -435,6 +439,35 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
|
||||
}
|
||||
|
||||
private static final class ExpressionBasedAuthorizationManager
|
||||
implements AuthorizationManager<MessageAuthorizationContext<?>> {
|
||||
|
||||
private final SecurityExpressionHandler<MessageAuthorizationContext<?>> expressionHandler;
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
private ExpressionBasedAuthorizationManager(String expression) {
|
||||
this(new MessageAuthorizationContextSecurityExpressionHandler(), expression);
|
||||
}
|
||||
|
||||
private ExpressionBasedAuthorizationManager(
|
||||
SecurityExpressionHandler<MessageAuthorizationContext<?>> expressionHandler, String expression) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
Assert.notNull(expression, "expression cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
|
||||
MessageAuthorizationContext<?> object) {
|
||||
EvaluationContext context = this.expressionHandler.createEvaluationContext(authentication, object);
|
||||
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, context);
|
||||
return new AuthorizationDecision(granted);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MessageMatcherDelegatingAuthorizationManagerFactory {
|
||||
|
||||
private static AuthorizationManager<Message<?>> createMessageMatcherDelegatingAuthorizationManager(
|
||||
|
||||
+5
-5
@@ -286,7 +286,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
||||
if (factoryOfRequestAuthorizationContext != null) {
|
||||
return factoryOfRequestAuthorizationContext
|
||||
}
|
||||
val factoryOfObjectType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory::class.java, Any::class.java)
|
||||
val factoryOfObjectType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory::class.java, Object::class.java)
|
||||
val factoryOfAny = context.getBeanProvider<AuthorizationManagerFactory<Any>>(factoryOfObjectType).getIfUnique()
|
||||
if (factoryOfAny != null) {
|
||||
return factoryOfAny
|
||||
@@ -303,20 +303,20 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
||||
return defaultFactory
|
||||
}
|
||||
|
||||
private fun resolveRolePrefix(context: ApplicationContext): String? {
|
||||
private fun resolveRolePrefix(context: ApplicationContext): String {
|
||||
val beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults::class.java)
|
||||
if (beanNames.isNotEmpty()) {
|
||||
return context.getBean(GrantedAuthorityDefaults::class.java).rolePrefix
|
||||
}
|
||||
return null
|
||||
return "ROLE_";
|
||||
}
|
||||
|
||||
private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy? {
|
||||
private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy {
|
||||
val beanNames = context.getBeanNamesForType(RoleHierarchy::class.java)
|
||||
if (beanNames.isNotEmpty()) {
|
||||
return context.getBean(RoleHierarchy::class.java)
|
||||
}
|
||||
return null
|
||||
return NullRoleHierarchy()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-4
@@ -37,11 +37,9 @@ class HeadersDsl {
|
||||
private var cacheControl: ((HeadersConfigurer<HttpSecurity>.CacheControlConfig) -> Unit)? = null
|
||||
private var hsts: ((HeadersConfigurer<HttpSecurity>.HstsConfig) -> Unit)? = null
|
||||
private var frameOptions: ((HeadersConfigurer<HttpSecurity>.FrameOptionsConfig) -> Unit)? = null
|
||||
@Suppress("DEPRECATION")
|
||||
private var hpkp: ((HeadersConfigurer<HttpSecurity>.HpkpConfig) -> Unit)? = null
|
||||
private var contentSecurityPolicy: ((HeadersConfigurer<HttpSecurity>.ContentSecurityPolicyConfig) -> Unit)? = null
|
||||
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
|
||||
@Suppress("DEPRECATION")
|
||||
private var featurePolicyDirectives: String? = null
|
||||
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
|
||||
private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null
|
||||
@@ -122,7 +120,6 @@ class HeadersDsl {
|
||||
* @deprecated see <a href="https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate and Public Key Pinning</a> for more context
|
||||
*/
|
||||
@Deprecated(message = "as of 5.8 with no replacement")
|
||||
@Suppress("DEPRECATION")
|
||||
fun httpPublicKeyPinning(hpkpConfig: HttpPublicKeyPinningDsl.() -> Unit) {
|
||||
this.hpkp = HttpPublicKeyPinningDsl().apply(hpkpConfig).get()
|
||||
}
|
||||
@@ -170,7 +167,6 @@ class HeadersDsl {
|
||||
* @param policyDirectives policyDirectives the security policy directive(s)
|
||||
*/
|
||||
@Deprecated("Use 'permissionsPolicy { }' instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
fun featurePolicy(policyDirectives: String) {
|
||||
this.featurePolicyDirectives = policyDirectives
|
||||
}
|
||||
|
||||
-1
@@ -614,7 +614,6 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
||||
* @see [RequiresChannelDsl]
|
||||
* @deprecated please use [redirectToHttps] instead
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated(message="since 6.5 use redirectToHttps instead")
|
||||
fun requiresChannel(requiresChannelConfiguration: RequiresChannelDsl.() -> Unit) {
|
||||
val requiresChannelCustomizer = RequiresChannelDsl().apply(requiresChannelConfiguration).get()
|
||||
|
||||
-2
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.springframework.security.config.annotation.web
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
|
||||
@@ -62,7 +62,6 @@ class X509Dsl {
|
||||
authenticationDetailsSource?.also { x509.authenticationDetailsSource(authenticationDetailsSource) }
|
||||
userDetailsService?.also { x509.userDetailsService(userDetailsService) }
|
||||
authenticationUserDetailsService?.also { x509.authenticationUserDetailsService(authenticationUserDetailsService) }
|
||||
@Suppress("DEPRECATION")
|
||||
subjectPrincipalRegex?.also { x509.subjectPrincipalRegex(subjectPrincipalRegex) }
|
||||
}
|
||||
}
|
||||
|
||||
-2
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.springframework.security.config.annotation.web.headers
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
|
||||
+2
-1
@@ -68,11 +68,12 @@ class SessionFixationDsl {
|
||||
internal fun get(): (SessionManagementConfigurer<HttpSecurity>.SessionFixationConfigurer) -> Unit {
|
||||
return { sessionFixation ->
|
||||
strategy?.also {
|
||||
when (it) {
|
||||
when (strategy) {
|
||||
SessionFixationStrategy.NEW -> sessionFixation.newSession()
|
||||
SessionFixationStrategy.MIGRATE -> sessionFixation.migrateSession()
|
||||
SessionFixationStrategy.CHANGE_ID -> sessionFixation.changeSessionId()
|
||||
SessionFixationStrategy.NONE -> sessionFixation.none()
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# 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
|
||||
@@ -44,8 +42,7 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.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.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.xsd=org/springframework/security/config/spring-security-7.0.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
@@ -86,6 +86,9 @@ 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;
|
||||
@@ -162,6 +165,7 @@ 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;
|
||||
@@ -169,15 +173,22 @@ 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;
|
||||
@@ -191,6 +202,7 @@ 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;
|
||||
@@ -246,15 +258,13 @@ import org.springframework.security.web.savedrequest.SimpleSavedRequest;
|
||||
import org.springframework.security.web.server.firewall.ServerExchangeRejectedException;
|
||||
import org.springframework.security.web.session.HttpSessionCreatedEvent;
|
||||
import org.springframework.security.web.session.HttpSessionIdChangedEvent;
|
||||
import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
|
||||
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.AuthenticatorSelectionCriteria;
|
||||
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.COSEAlgorithmIdentifier;
|
||||
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
|
||||
import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
|
||||
@@ -262,17 +272,13 @@ import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExte
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
|
||||
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialParameters;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
|
||||
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.TestPublicKeyCredentialCreationOptions;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials;
|
||||
@@ -280,7 +286,6 @@ import org.springframework.security.web.webauthn.api.UserVerificationRequirement
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication;
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken;
|
||||
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
|
||||
import org.springframework.security.web.webauthn.management.TestPublicKeyCredentialRpEntities;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
final class SerializationSamples {
|
||||
@@ -294,14 +299,6 @@ final class SerializationSamples {
|
||||
Authentication authentication = TestAuthentication.authenticated(user);
|
||||
SecurityContext securityContext = new SecurityContextImpl(authentication);
|
||||
|
||||
instancioByClassName.put(OneTimeTokenAuthenticationToken.class, () -> {
|
||||
@SuppressWarnings("removal")
|
||||
InstancioOfClassApi<?> instancio = Instancio.of(OneTimeTokenAuthenticationToken.class);
|
||||
instancio.supply(Select.all(OneTimeTokenAuthenticationToken.class),
|
||||
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("token")));
|
||||
return instancio;
|
||||
});
|
||||
|
||||
// oauth2-core
|
||||
generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create());
|
||||
generatorByClassName.put(OAuth2AuthorizationRequest.class,
|
||||
@@ -445,6 +442,8 @@ 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")
|
||||
@@ -470,6 +469,58 @@ 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(),
|
||||
@@ -615,7 +666,8 @@ final class SerializationSamples {
|
||||
token.setDetails(details);
|
||||
return token;
|
||||
});
|
||||
|
||||
generatorByClassName.put(OneTimeTokenAuthenticationToken.class,
|
||||
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token")));
|
||||
generatorByClassName.put(OneTimeTokenAuthentication.class,
|
||||
(r) -> applyDetails(new OneTimeTokenAuthentication("username", authentication.getAuthorities())));
|
||||
generatorByClassName.put(AccessDeniedException.class,
|
||||
@@ -685,6 +737,12 @@ 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",
|
||||
@@ -875,6 +933,8 @@ 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);
|
||||
@@ -896,36 +956,6 @@ final class SerializationSamples {
|
||||
generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class,
|
||||
(r) -> new CredentialPropertiesOutput(true).getOutput());
|
||||
|
||||
AttestationConveyancePreference attestationConveyancePreference = AttestationConveyancePreference.DIRECT;
|
||||
ResidentKeyRequirement residentKeyRequirement = ResidentKeyRequirement.REQUIRED;
|
||||
AuthenticatorSelectionCriteria authenticatorSelectionCriteria = AuthenticatorSelectionCriteria.builder()
|
||||
.authenticatorAttachment(AuthenticatorAttachment.PLATFORM)
|
||||
.residentKey(residentKeyRequirement)
|
||||
.userVerification(UserVerificationRequirement.REQUIRED)
|
||||
.build();
|
||||
PublicKeyCredentialParameters publicKeyCredentialParameters = PublicKeyCredentialParameters.RS256;
|
||||
PublicKeyCredentialRpEntity publicKeyCredentialRpEntity = TestPublicKeyCredentialRpEntities.createRpEntity()
|
||||
.build();
|
||||
|
||||
generatorByClassName.put(AttestationConveyancePreference.class, (r) -> attestationConveyancePreference);
|
||||
generatorByClassName.put(ResidentKeyRequirement.class, (r) -> residentKeyRequirement);
|
||||
generatorByClassName.put(AuthenticatorSelectionCriteria.class, (r) -> authenticatorSelectionCriteria);
|
||||
generatorByClassName.put(COSEAlgorithmIdentifier.class, ((r) -> COSEAlgorithmIdentifier.RS256));
|
||||
generatorByClassName.put(PublicKeyCredentialParameters.class, (r) -> publicKeyCredentialParameters);
|
||||
generatorByClassName.put(PublicKeyCredentialRpEntity.class, (r) -> publicKeyCredentialRpEntity);
|
||||
generatorByClassName.put(PublicKeyCredentialCreationOptions.class,
|
||||
(o) -> TestPublicKeyCredentialCreationOptions.createPublicKeyCredentialCreationOptions()
|
||||
.extensions(inputs)
|
||||
.attestation(attestationConveyancePreference)
|
||||
.authenticatorSelection(authenticatorSelectionCriteria)
|
||||
.challenge(TestBytes.get())
|
||||
.excludeCredentials(List.of(descriptor))
|
||||
.rp(publicKeyCredentialRpEntity)
|
||||
.pubKeyCredParams(publicKeyCredentialParameters)
|
||||
.timeout(Duration.ofMinutes(5))
|
||||
.user(TestPublicKeyCredentialUserEntities.userEntity().id(TestBytes.get()).build())
|
||||
.build());
|
||||
|
||||
// One-Time Token
|
||||
DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user",
|
||||
Instant.now().plusSeconds(300));
|
||||
|
||||
+54
-5
@@ -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,10 +207,7 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
boolean hasSerialVersion = Stream.of(clazz.getDeclaredFields())
|
||||
.map(Field::getName)
|
||||
.anyMatch((n) -> n.equals("serialVersionUID"));
|
||||
SuppressWarnings suppressWarnings = clazz.getAnnotation(SuppressWarnings.class);
|
||||
boolean hasSerialIgnore = suppressWarnings == null
|
||||
|| Arrays.asList(suppressWarnings.value()).contains("Serial");
|
||||
if (!hasSerialVersion && !hasSerialIgnore) {
|
||||
if (!hasSerialVersion && !hasSuppressSerialInSource(clazz)) {
|
||||
classes.add(clazz);
|
||||
continue;
|
||||
}
|
||||
@@ -249,6 +246,58 @@ 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("\\.");
|
||||
|
||||
+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.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd");
|
||||
"You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd");
|
||||
}
|
||||
|
||||
// SEC-1868
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ public class NamespaceHttpTests {
|
||||
// @formatter:off
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -222,8 +222,7 @@ public class WebSecurityConfigurationTests {
|
||||
// SEC-2773
|
||||
@Test
|
||||
public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationThenIsStatic() {
|
||||
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener",
|
||||
(Class<?>[]) null);
|
||||
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||
}
|
||||
|
||||
|
||||
-45
@@ -16,7 +16,6 @@
|
||||
|
||||
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;
|
||||
|
||||
@@ -24,8 +23,6 @@ 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;
|
||||
@@ -37,14 +34,11 @@ 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;
|
||||
@@ -107,45 +101,6 @@ 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,6 +452,18 @@ 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();
|
||||
@@ -1359,6 +1371,32 @@ 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 {
|
||||
|
||||
-4
@@ -1201,7 +1201,6 @@ public class HeadersConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@SuppressWarnings("removal")
|
||||
static class PermissionsPolicyConfig {
|
||||
|
||||
@Bean
|
||||
@@ -1222,7 +1221,6 @@ public class HeadersConfigurerTests {
|
||||
static class PermissionsPolicyStringConfig {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
@@ -1237,7 +1235,6 @@ public class HeadersConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@SuppressWarnings("removal")
|
||||
static class PermissionsPolicyInvalidConfig {
|
||||
|
||||
@Bean
|
||||
@@ -1255,7 +1252,6 @@ public class HeadersConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@SuppressWarnings("removal")
|
||||
static class PermissionsPolicyInvalidStringConfig {
|
||||
|
||||
@Bean
|
||||
|
||||
+2
-2
@@ -103,7 +103,7 @@ public class HttpBasicConfigurerTests {
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public class HttpBasicConfigurerTests {
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
+105
@@ -125,6 +125,34 @@ 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);
|
||||
@@ -430,6 +458,83 @@ 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 {
|
||||
|
||||
|
||||
+4
-4
@@ -71,7 +71,7 @@ public class NamespaceHttpBasicTests {
|
||||
// @formatter:off
|
||||
this.mvc.perform(requestWithInvalidPassword)
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
|
||||
// @formatter:on
|
||||
MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password"));
|
||||
this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound());
|
||||
@@ -85,7 +85,7 @@ public class NamespaceHttpBasicTests {
|
||||
// @formatter:off
|
||||
this.mvc.perform(requestWithInvalidPassword)
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
|
||||
// @formatter:on
|
||||
MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password"));
|
||||
this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound());
|
||||
@@ -101,7 +101,7 @@ public class NamespaceHttpBasicTests {
|
||||
// @formatter:off
|
||||
this.mvc.perform(requestWithInvalidPassword)
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class NamespaceHttpBasicTests {
|
||||
// @formatter:off
|
||||
this.mvc.perform(requestWithInvalidPassword)
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\", charset=\"UTF-8\""));
|
||||
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
+69
@@ -43,9 +43,16 @@ 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;
|
||||
@@ -58,6 +65,7 @@ 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;
|
||||
@@ -257,6 +265,24 @@ 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 {
|
||||
@@ -475,4 +501,47 @@ 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -1257,7 +1257,6 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user