Compare commits

..

No commits in common. "main" and "6.5.8" have entirely different histories.
main ... 6.5.8

3684 changed files with 54921 additions and 163801 deletions

145
.github/dependabot.yml vendored
View File

@ -1,12 +1,11 @@
version: 2 version: 2
registries: registries:
shibboleth: spring-milestones:
type: maven-repository type: maven-repository
url: https://build.shibboleth.net/maven/releases url: https://repo.spring.io/milestone
updates: updates:
# 6.5.x
- package-ecosystem: gradle - package-ecosystem: gradle
target-branch: 6.5.x target-branch: 6.4.x
directory: / directory: /
schedule: schedule:
interval: daily interval: daily
@ -15,7 +14,7 @@ updates:
labels: labels:
- 'type: dependency-upgrade' - 'type: dependency-upgrade'
registries: registries:
- shibboleth - spring-milestones
ignore: ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt - dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython - dependency-name: org.python:jython
@ -31,28 +30,8 @@ updates:
update-types: update-types:
- version-update:semver-major - version-update:semver-major
- version-update:semver-minor - 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 - package-ecosystem: gradle
target-branch: 7.0.x target-branch: 6.3.x
directory: / directory: /
schedule: schedule:
interval: daily interval: daily
@ -61,10 +40,9 @@ updates:
labels: labels:
- 'type: dependency-upgrade' - 'type: dependency-upgrade'
registries: registries:
- shibboleth - spring-milestones
ignore: ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt - dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: io.spring.nullability:*
- dependency-name: org.python:jython - dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:* - dependency-name: org.apache.directory.server:*
- dependency-name: org.apache.directory.shared:* - dependency-name: org.apache.directory.shared:*
@ -74,34 +52,10 @@ updates:
- dependency-name: org.mockito:mockito-bom - dependency-name: org.mockito:mockito-bom
update-types: update-types:
- version-update:semver-major - version-update:semver-major
- dependency-name: com.gradle.enterprise
update-types:
- version-update:semver-major
- version-update:semver-minor
- dependency-name: '*' - dependency-name: '*'
update-types: update-types:
- version-update:semver-major - version-update:semver-major
- version-update:semver-minor - 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 - package-ecosystem: gradle
target-branch: main target-branch: main
directory: / directory: /
@ -112,7 +66,7 @@ updates:
labels: labels:
- 'type: dependency-upgrade' - 'type: dependency-upgrade'
registries: registries:
- shibboleth - spring-milestones
ignore: ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt - dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython - dependency-name: org.python:jython
@ -131,6 +85,36 @@ updates:
- dependency-name: '*' - dependency-name: '*'
update-types: update-types:
- version-update:semver-major - version-update:semver-major
- version-update:semver-minor
- package-ecosystem: github-actions
target-branch: 6.3.x
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
ignore:
- dependency-name: sjohnr/*
- package-ecosystem: github-actions
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
- package-ecosystem: npm
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
- package-ecosystem: npm - package-ecosystem: npm
target-branch: main target-branch: main
directory: /docs directory: /docs
@ -138,63 +122,12 @@ updates:
interval: weekly interval: weekly
labels: labels:
- 'type: task' - 'type: task'
- 'type: dependency-upgrade'
- 'in: build' - '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 - package-ecosystem: npm
target-branch: docs-build target-branch: 6.3.x
directory: / directory: /docs
schedule: schedule:
interval: weekly interval: weekly
labels: labels:
- 'type: task' - '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' - 'in: build'

View File

@ -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

View File

@ -1,36 +0,0 @@
name: CI
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
permissions:
contents: read
jobs:
snapshot-test:
name: Test Against Snapshots
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
strategy:
matrix:
include:
- java-version: 25
toolchain: 25
with:
java-version: ${{ matrix.java-version }}
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
secrets: inherit
send-notification:
name: Send Notification
needs: [ snapshot-test ]
if: ${{ !success() }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}

View File

@ -21,28 +21,62 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ ubuntu-latest, windows-latest ] os: [ ubuntu-latest, windows-latest ]
jdk: [ 25 ] jdk: [ 17 ]
with: with:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
java-version: ${{ matrix.jdk }} java-version: ${{ matrix.jdk }}
distribution: temurin distribution: temurin
secrets: inherit secrets: inherit
test:
name: Test Against Snapshots
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
strategy:
matrix:
include:
- java-version: 21-ea
toolchain: 21
- java-version: 17
toolchain: 17
with:
java-version: ${{ matrix.java-version }}
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.2.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2024.0.+ --stacktrace
secrets: inherit
check-samples:
name: Check Samples
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'spring-projects' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@v2
with:
java-version: 17
distribution: temurin
- name: Check samples project
env:
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
SAMPLES_DIR: ../spring-security-samples
run: |
# Extract version from gradle.properties
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
# Extract samplesBranch from gradle.properties
samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}')
./gradlew publishMavenJavaPublicationToLocalRepository
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR"
./gradlew --refresh-dependencies --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" test integrationTest
deploy-artifacts: deploy-artifacts:
name: Deploy Artifacts name: Deploy Artifacts
needs: [ build] needs: [ build, test, check-samples ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14 uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
with: with:
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }} should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
default-publish-milestones-central: true
java-version: 25
secrets: inherit secrets: inherit
deploy-schema: deploy-schema:
name: Deploy Schema name: Deploy Schema
needs: [ build ] needs: [ build, test, check-samples ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14 uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
with: with:
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }} should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
java-version: 25
secrets: inherit secrets: inherit
perform-release: perform-release:
name: Perform Release name: Perform Release
@ -51,11 +85,10 @@ jobs:
with: with:
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }} should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
project-version: ${{ needs.deploy-artifacts.outputs.project-version }} project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
milestone-repo-url: https://repo1.maven.org/maven2 milestone-repo-url: https://repo.spring.io/artifactory/milestone
release-repo-url: https://repo1.maven.org/maven2 release-repo-url: https://repo1.maven.org/maven2
artifact-path: org/springframework/security/spring-security-core artifact-path: org/springframework/security/spring-security-core
slack-announcing-id: spring-security-announcing slack-announcing-id: spring-security-announcing
java-version: 25
secrets: inherit secrets: inherit
send-notification: send-notification:
name: Send Notification name: Send Notification

View File

@ -1,27 +0,0 @@
name: Finalize Release
on:
workflow_dispatch: # Manual trigger
inputs:
version:
description: The Spring Security release to finalize (e.g. 7.0.0-RC2)
required: true
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
permissions:
contents: read
jobs:
perform-release:
name: Perform Release
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
with:
should-perform-release: true
project-version: ${{ inputs.version }}
milestone-repo-url: https://repo1.maven.org/maven2
release-repo-url: https://repo1.maven.org/maven2
artifact-path: org/springframework/security/spring-security-core
slack-announcing-id: spring-security-announcing
secrets: inherit

View File

@ -9,7 +9,6 @@ permissions:
jobs: jobs:
upgrade_wrapper: upgrade_wrapper:
name: Execution name: Execution
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Set up Git configuration - name: Set up Git configuration
@ -21,10 +20,10 @@ jobs:
git config --global user.email 'github-actions[bot]@users.noreply.github.com' git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 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 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with: with:
java-version: '25' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Set up Gradle - name: Set up Gradle
uses: gradle/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1

View File

@ -15,7 +15,7 @@ jobs:
- name: Set up gradle - name: Set up gradle
uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5 uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5
with: with:
java-version: '25' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan
@ -28,13 +28,13 @@ jobs:
- name: Set up gradle - name: Set up gradle
uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5 uses: spring-io/spring-gradle-build-action@efc55f07f4dfa22f2afd97f9ea1be4212eeed737 # v2.0.5
with: with:
java-version: '25' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Run Antora - name: Run Antora
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
- name: Upload Docs - name: Upload Docs
id: upload id: upload
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with: with:
name: docs name: docs
path: docs/build/site path: docs/build/site

View File

@ -11,7 +11,7 @@ jobs:
strategy: strategy:
matrix: matrix:
# List of active maintenance branches. # List of active maintenance branches.
branch: [ main, 7.0.x, 6.5.x, 6.4.x, 6.3.x ] branch: [ main, 6.4.x, 6.3.x ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout

View File

@ -12,12 +12,11 @@ permissions:
jobs: jobs:
update-antora-ui-spring: update-antora-ui-spring:
name: Update on Supported Branches
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Update on Supported Branches
strategy: strategy:
matrix: matrix:
branch: [ '6.5.x', '7.0.x', 'main' ] branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ]
steps: steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf - uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf
name: Update name: Update
@ -26,9 +25,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
antora-file-path: 'docs/antora-playbook.yml' antora-file-path: 'docs/antora-playbook.yml'
update-antora-ui-spring-docs-build: update-antora-ui-spring-docs-build:
name: Update on docs-build
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Update on docs-build
steps: steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf - uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf
name: Update name: Update

1
.gitignore vendored
View File

@ -25,7 +25,6 @@ atlassian-ide-plugin.xml
s101plugin.state s101plugin.state
.attach_pid* .attach_pid*
.~lock.*# .~lock.*#
.kotlin/
!.idea/checkstyle-idea.xml !.idea/checkstyle-idea.xml
!.idea/externalDependencies.xml !.idea/externalDependencies.xml

View File

@ -3,4 +3,4 @@
# See https://sdkman.io/usage#config # See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config # A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true # sdkman_auto_env=true
java=25-librca java=17.0.3-tem

View File

@ -1,3 +1,3 @@
{ {
"java.gradle.buildServer.enabled": "off" "java.import.gradle.enabled": false
} }

View File

@ -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]. 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. 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. Reading those discussions helps you to learn about the issue, and helps us to make a decision.
[[find-an-issue]] [[find-an-issue]]
@ -79,9 +79,6 @@ See https://github.com/spring-projects/spring-security/tree/main#building-from-s
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize. The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
Additionally, since Streams are https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loops, please use them judiciously.
The team may ask you to change to a `for` loop if the given code is along a hot path.
To format the code as well as check the style, run `./gradlew format && ./gradlew check`. To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
[[submit-a-pull-request]] [[submit-a-pull-request]]
@ -94,7 +91,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. 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]. 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. For typos and straightforward bug fixes, starting with a pull request is encouraged.
Please include a description for context and motivation. 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. Note that the team may close your pull request if it's not a fit for the project.

View File

@ -68,27 +68,6 @@ The https://github.com/spring-projects/spring-security/tree/docs-build[playbook
Discover more commands with `./gradlew tasks`. Discover more commands with `./gradlew tasks`.
=== IDE setup (IntelliJ)
No special steps are needed to open Spring Security in IntelliJ.
=== IDE setup (Eclipse and VS Code)
To work in Eclipse or VS Code, first generate Eclipse metadata so you can import the project into Eclipse or VS Code:
[indent=0]
----
./gradlew cleanEclipse eclipse
----
If you have not built the project yet, run `./gradlew publishToMavenLocal` first so dependencies are resolved.
*VS Code:* Open the repository root as a folder. The repository includes `.vscode/settings.json` which disables automatic Gradle import so that the generated Eclipse metadata (`.classpath`, `.project`) is used. Do not use the Gradle for Java extension to import the project.
*Eclipse:* File → Import → General → Existing Projects into Workspace, then select the repository root.
The build uses a custom Eclipse plugin to work around Gradle dependency cycles that confuse IDE metadata generation. You may see Eclipse warnings about `xml-apis` from some test dependencies; those are excluded in the build and can be ignored.
== Getting Support == Getting Support
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow]. Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
https://spring.io/support[Commercial support] is available too. https://spring.io/support[Commercial support] is available too.

View File

@ -1,54 +0,0 @@
plugins {
id 'compile-warnings-error'
id 'javadoc-warnings-error'
}
apply plugin: 'io.spring.convention.spring-module'
dependencies {
management platform(project(":spring-security-dependencies"))
api project(':spring-security-crypto')
api project(':spring-security-core')
api 'org.springframework:spring-aop'
api 'org.springframework:spring-beans'
api 'org.springframework:spring-context'
api 'org.springframework:spring-core'
api 'org.springframework:spring-expression'
api 'io.micrometer:micrometer-observation'
optional project(':spring-security-acl')
optional project(':spring-security-messaging')
optional project(':spring-security-web')
optional 'org.springframework:spring-websocket'
optional 'com.fasterxml.jackson.core:jackson-databind'
optional 'io.micrometer:context-propagation'
optional 'io.projectreactor:reactor-core'
optional 'jakarta.annotation:jakarta.annotation-api'
optional 'org.aspectj:aspectjrt'
optional 'org.springframework:spring-jdbc'
optional 'org.springframework:spring-tx'
optional 'org.jetbrains.kotlinx:kotlinx-coroutines-reactor'
provided 'jakarta.servlet:jakarta.servlet-api'
testImplementation project(path : ':spring-security-web', configuration : 'tests')
testImplementation 'commons-collections:commons-collections'
testImplementation 'io.projectreactor:reactor-test'
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation "org.springframework:spring-core-test"
testImplementation "org.springframework:spring-test"
testImplementation 'org.skyscreamer:jsonassert'
testImplementation 'org.springframework:spring-test'
testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation 'io.mockk:mockk'
testRuntimeOnly 'org.hsqldb:hsqldb'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* 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.access;
/**
* Represents the interface of a secured object.
*
* @author Ben Alex
*/
public interface ITargetObject {
Integer computeHashCode(String input);
int countLength(String input);
String makeLowerCase(String input);
String makeUpperCase(String input);
String publicMakeLowerCase(String input);
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* 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.access;
/**
* Simply extends {@link TargetObject} so we have a different object to put configuration
* attributes against.
* <P>
* There is no different behaviour. We have to define each method so that
* <code>Class.getMethod(methodName, args)</code> returns a <code>Method</code>
* referencing this class rather than the parent class.
* </p>
* <P>
* We need to implement <code>ITargetObject</code> again because the
* <code>MethodDefinitionAttributes</code> only locates attributes on interfaces
* explicitly defined by the intercepted class (not the interfaces defined by its parent
* class or classes).
* </p>
*
* @author Ben Alex
*/
public class OtherTargetObject extends TargetObject implements ITargetObject {
@Override
public String makeLowerCase(String input) {
return super.makeLowerCase(input);
}
@Override
public String makeUpperCase(String input) {
return super.makeUpperCase(input);
}
@Override
public String publicMakeLowerCase(String input) {
return super.publicMakeLowerCase(input);
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* 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.access;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Represents a secured object.
*
* @author Ben Alex
*/
public class TargetObject implements ITargetObject {
@Override
public Integer computeHashCode(String input) {
return input.hashCode();
}
@Override
public int countLength(String input) {
return input.length();
}
/**
* Returns the lowercase string, followed by security environment information.
* @param input the message to make lowercase
* @return the lowercase message, a space, the <code>Authentication</code> class that
* was on the <code>SecurityContext</code> at the time of method invocation, and a
* boolean indicating if the <code>Authentication</code> object is authenticated or
* not
*/
@Override
public String makeLowerCase(String input) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null) {
return input.toLowerCase() + " Authentication empty";
}
else {
return input.toLowerCase() + " " + auth.getClass().getName() + " " + auth.isAuthenticated();
}
}
/**
* Returns the uppercase string, followed by security environment information.
* @param input the message to make uppercase
* @return the uppercase message, a space, the <code>Authentication</code> class that
* was on the <code>SecurityContext</code> at the time of method invocation, and a
* boolean indicating if the <code>Authentication</code> object is authenticated or
* not
*/
@Override
public String makeUpperCase(String input) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return input.toUpperCase() + " " + auth.getClass().getName() + " " + auth.isAuthenticated();
}
/**
* Delegates through to the {@link #makeLowerCase(String)} method.
* @param input the message to be made lower-case
*/
@Override
public String publicMakeLowerCase(String input) {
return this.makeLowerCase(input);
}
}

View File

@ -1,9 +1,3 @@
plugins {
id 'compile-warnings-error'
id 'javadoc-warnings-error'
id 'security-nullability'
}
apply plugin: 'io.spring.convention.spring-module' apply plugin: 'io.spring.convention.spring-module'
dependencies { dependencies {

View File

@ -71,7 +71,7 @@ import org.springframework.util.StringUtils;
* <tt>AclEntryVoter</tt>: * <tt>AclEntryVoter</tt>:
* <ul> * <ul>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute * <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_READ</code>, require permission * <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission
* <code>BasePermission.READ</code></li> * <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute * <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list * <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list

View File

@ -23,7 +23,6 @@ import java.util.Locale;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage; import org.springframework.core.log.LogMessage;
import org.springframework.security.access.PermissionEvaluator; 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 * 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 * 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 * @author Luke Taylor
* @since 3.0 * @since 3.0
@ -74,7 +73,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
* be overridden using a null check in the expression itself). * be overridden using a null check in the expression itself).
*/ */
@Override @Override
public boolean hasPermission(Authentication authentication, @Nullable Object domainObject, Object permission) { public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
if (domainObject == null) { if (domainObject == null) {
return false; return false;
} }

View File

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

View File

@ -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;

View File

@ -18,8 +18,6 @@ package org.springframework.security.acls.domain;
import java.io.Serializable; import java.io.Serializable;
import org.jspecify.annotations.Nullable;
import org.springframework.security.acls.model.AccessControlEntry; import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl; import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAccessControlEntry; import org.springframework.security.acls.model.AuditableAccessControlEntry;
@ -38,7 +36,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
private Permission permission; private Permission permission;
private final @Nullable Serializable id; private final Serializable id;
private final Sid sid; private final Sid sid;
@ -48,7 +46,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
private final boolean granting; 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) { boolean auditSuccess, boolean auditFailure) {
Assert.notNull(acl, "Acl required"); Assert.notNull(acl, "Acl required");
Assert.notNull(sid, "Sid required"); Assert.notNull(sid, "Sid required");
@ -135,7 +133,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
} }
@Override @Override
public @Nullable Serializable getId() { public Serializable getId() {
return this.id; return this.id;
} }

View File

@ -20,7 +20,7 @@ import org.springframework.security.acls.model.Acl;
/** /**
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call * Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
* administrative methods on the <code>AclImpl</code>. * adminstrative methods on the <code>AclImpl</code>.
* *
* @author Ben Alex * @author Ben Alex
*/ */

View File

@ -99,8 +99,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
Authentication authentication = context.getAuthentication(); Authentication authentication = context.getAuthentication();
// Check if authorized by virtue of ACL ownership // Check if authorized by virtue of ACL ownership
Sid currentUser = createCurrentUser(authentication); Sid currentUser = createCurrentUser(authentication);
Sid owner = acl.getOwner(); if (currentUser.equals(acl.getOwner())
if (owner != null && currentUser.equals(owner)
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) { && ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
return; return;
} }
@ -109,8 +108,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy
.getReachableGrantedAuthorities(authentication.getAuthorities()); .getReachableGrantedAuthorities(authentication.getAuthorities());
Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities); Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities);
if (owner instanceof GrantedAuthoritySid if (acl.getOwner() instanceof GrantedAuthoritySid
&& authorities.contains(((GrantedAuthoritySid) owner).getGrantedAuthority())) { && authorities.contains(((GrantedAuthoritySid) acl.getOwner()).getGrantedAuthority())) {
return; return;
} }

View File

@ -20,8 +20,6 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.security.acls.model.AccessControlEntry; import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl; import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAcl; import org.springframework.security.acls.model.AuditableAcl;
@ -43,7 +41,7 @@ import org.springframework.util.ObjectUtils;
*/ */
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl { public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
private @Nullable Acl parentAcl; private Acl parentAcl;
private transient AclAuthorizationStrategy aclAuthorizationStrategy; private transient AclAuthorizationStrategy aclAuthorizationStrategy;
@ -56,10 +54,10 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
private Serializable id; private Serializable id;
// OwnershipAcl // OwnershipAcl
private @Nullable Sid owner; private Sid owner;
// includes all SIDs the WHERE clause covered, even if there was no ACE for a SID // 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; private boolean entriesInheriting = true;
@ -99,8 +97,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
* @param owner the owner (required) * @param owner the owner (required)
*/ */
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy, public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
PermissionGrantingStrategy grantingStrategy, @Nullable Acl parentAcl, @Nullable List<Sid> loadedSids, PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting,
boolean entriesInheriting, Sid owner) { Sid owner) {
Assert.notNull(objectIdentity, "Object Identity required"); Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required"); Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy 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 * Private no-argument constructor for use by reflection-based persistence tools along
* with field-level access. * with field-level access.
*/ */
@SuppressWarnings({ "unused", "NullAway.Init" }) @SuppressWarnings("unused")
private AclImpl() { private AclImpl() {
} }
@ -201,7 +199,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
} }
@Override @Override
public boolean isSidLoaded(@Nullable List<Sid> sids) { public boolean isSidLoaded(List<Sid> sids) {
// If loadedSides is null, this indicates all SIDs were loaded // If loadedSides is null, this indicates all SIDs were loaded
// Also return true if the caller didn't specify a SID to find // Also return true if the caller didn't specify a SID to find
if ((this.loadedSids == null) || (sids == null) || sids.isEmpty()) { if ((this.loadedSids == null) || (sids == null) || sids.isEmpty()) {
@ -240,19 +238,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
} }
@Override @Override
public @Nullable Sid getOwner() { public Sid getOwner() {
return this.owner; return this.owner;
} }
@Override @Override
public void setParent(@Nullable Acl newParent) { public void setParent(Acl newParent) {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL); this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself"); Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
this.parentAcl = newParent; this.parentAcl = newParent;
} }
@Override @Override
public @Nullable Acl getParentAcl() { public Acl getParentAcl() {
return this.parentAcl; return this.parentAcl;
} }

View File

@ -42,7 +42,7 @@ public class GrantedAuthoritySid implements Sid {
public GrantedAuthoritySid(GrantedAuthority grantedAuthority) { public GrantedAuthoritySid(GrantedAuthority grantedAuthority) {
Assert.notNull(grantedAuthority, "GrantedAuthority required"); Assert.notNull(grantedAuthority, "GrantedAuthority required");
Assert.notNull(grantedAuthority.getAuthority(), Assert.notNull(grantedAuthority.getAuthority(),
"This Sid is only compatible with GrantedAuthority that provide a non-null getAuthority()"); "This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()");
this.grantedAuthority = grantedAuthority.getAuthority(); this.grantedAuthority = grantedAuthority.getAuthority();
} }

View File

@ -18,8 +18,6 @@ package org.springframework.security.acls.domain;
import java.io.Serializable; import java.io.Serializable;
import org.jspecify.annotations.Nullable;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.security.acls.model.AclCache; import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl; import org.springframework.security.acls.model.MutableAcl;
@ -80,13 +78,13 @@ public class SpringCacheBasedAclCache implements AclCache {
} }
@Override @Override
public @Nullable MutableAcl getFromCache(ObjectIdentity objectIdentity) { public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required"); Assert.notNull(objectIdentity, "ObjectIdentity required");
return getFromCache((Object) objectIdentity); return getFromCache((Object) objectIdentity);
} }
@Override @Override
public @Nullable MutableAcl getFromCache(Serializable pk) { public MutableAcl getFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required"); Assert.notNull(pk, "Primary key (identifier) required");
return getFromCache((Object) pk); return getFromCache((Object) pk);
} }
@ -103,16 +101,12 @@ public class SpringCacheBasedAclCache implements AclCache {
this.cache.put(acl.getId(), acl); this.cache.put(acl.getId(), acl);
} }
private @Nullable MutableAcl getFromCache(Object key) { private MutableAcl getFromCache(Object key) {
Cache.ValueWrapper element = this.cache.get(key); Cache.ValueWrapper element = this.cache.get(key);
if (element == null) { if (element == null) {
return null; return null;
} }
Object value = element.get(); return initializeTransientFields((MutableAcl) element.get());
if (value == null) {
return null;
}
return initializeTransientFields((MutableAcl) value);
} }
private MutableAcl initializeTransientFields(MutableAcl value) { private MutableAcl initializeTransientFields(MutableAcl value) {

View File

@ -17,7 +17,4 @@
/** /**
* Basic implementation of access control lists (ACLs) interfaces. * Basic implementation of access control lists (ACLs) interfaces.
*/ */
@NullMarked
package org.springframework.security.acls.domain; package org.springframework.security.acls.domain;
import org.jspecify.annotations.NullMarked;

View File

@ -23,7 +23,6 @@ import java.util.UUID;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService; 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. * @return The identifier in the appropriate target Java type. Typically Long or UUID.
* @throws SQLException * @throws SQLException
*/ */
@Nullable Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException { Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
Class<? extends Serializable> classIdType = classIdTypeFrom(resultSet); if (isString(identifier) && hasValidClassIdType(resultSet)
if (isString(identifier) && classIdType != null && canConvertFromStringTo(classIdType)) { && canConvertFromStringTo(classIdTypeFrom(resultSet))) {
return convertFromStringTo((String) identifier, classIdType); return convertFromStringTo((String) identifier, classIdTypeFrom(resultSet));
} }
// Assume it should be a Long type // Assume it should be a Long type
return convertToLong(identifier); return convertToLong(identifier);
@ -87,38 +86,28 @@ class AclClassIdUtils {
} }
} }
private @Nullable Class<? extends Serializable> classIdTypeFrom(ResultSet resultSet) throws SQLException { private <T extends Serializable> Class<T> classIdTypeFrom(ResultSet resultSet) throws SQLException {
try { return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
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 @Nullable Class<? extends Serializable> classIdTypeFrom(String className) { private <T extends Serializable> Class<T> classIdTypeFrom(String className) {
if (className == null) { if (className == null) {
return null; return null;
} }
try { try {
return Class.forName(className).asSubclass(Serializable.class); return (Class) Class.forName(className);
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
log.debug("Unable to find class id type on classpath", ex); log.debug("Unable to find class id type on classpath", ex);
return null; 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) { private <T> boolean canConvertFromStringTo(Class<T> targetType) {
return this.conversionService.canConvert(String.class, 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); return this.conversionService.convert(identifier, targetType);
} }
@ -132,7 +121,7 @@ class AclClassIdUtils {
* exception occurred * exception occurred
* @throws IllegalArgumentException if targetType is null * @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)) { if (this.conversionService.canConvert(identifier.getClass(), Long.class)) {
return this.conversionService.convert(identifier, Long.class); return this.conversionService.convert(identifier, Long.class);
} }
@ -151,10 +140,10 @@ class AclClassIdUtils {
private static class StringToLongConverter implements Converter<String, Long> { private static class StringToLongConverter implements Converter<String, Long> {
@Override @Override
public Long convert(@Nullable String identifierAsString) { public Long convert(String identifierAsString) {
if (identifierAsString == null) { if (identifierAsString == null) {
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class), throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(Long.class), identifierAsString, new NullPointerException()); TypeDescriptor.valueOf(Long.class), null, null);
} }
return Long.parseLong(identifierAsString); return Long.parseLong(identifierAsString);
@ -165,10 +154,10 @@ class AclClassIdUtils {
private static class StringToUUIDConverter implements Converter<String, UUID> { private static class StringToUUIDConverter implements Converter<String, UUID> {
@Override @Override
public UUID convert(@Nullable String identifierAsString) { public UUID convert(String identifierAsString) {
if (identifierAsString == null) { if (identifierAsString == null) {
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class), throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(UUID.class), identifierAsString, new NullPointerException()); TypeDescriptor.valueOf(UUID.class), null, null);
} }
return UUID.fromString(identifierAsString); return UUID.fromString(identifierAsString);

View File

@ -31,8 +31,6 @@ import java.util.Set;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
@ -67,11 +65,10 @@ import org.springframework.util.Assert;
* NB: This implementation does attempt to provide reasonably optimised lookups - within * NB: This implementation does attempt to provide reasonably optimised lookups - within
* the constraints of a normalised database and standard ANSI SQL features. If you are * the constraints of a normalised database and standard ANSI SQL features. If you are
* willing to sacrifice either of these constraints (e.g. use a particular database * willing to sacrifice either of these constraints (e.g. use a particular database
* feature such as hierarchical queries or materialized views, or reduce normalisation) * feature such as hierarchical queries or materalized views, or reduce normalisation) you
* you are likely to achieve better performance. In such situations you will need to * are likely to achieve better performance. In such situations you will need to provide
* provide your own custom <code>LookupStrategy</code>. This class does not support * your own custom <code>LookupStrategy</code>. This class does not support subclassing,
* subclassing, as it is likely to change in future releases and therefore subclassing is * as it is likely to change in future releases and therefore subclassing is unsupported.
* unsupported.
* <p> * <p>
* There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and * There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and
* one in <tt>lookupObjectIdentities</tt>. These are built from the same select and "order * one in <tt>lookupObjectIdentities</tt>. These are built from the same select and "order
@ -226,8 +223,7 @@ public class BasicLookupStrategy implements LookupStrategy {
* @param findNow Long-based primary keys to retrieve * @param findNow Long-based primary keys to retrieve
* @param sids * @param sids
*/ */
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow, private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow, final List<Sid> sids) {
final @Nullable List<Sid> sids) {
Assert.notNull(acls, "ACLs are required"); Assert.notNull(acls, "ACLs are required");
Assert.notEmpty(findNow, "Items to find now required"); Assert.notEmpty(findNow, "Items to find now required");
String sql = computeRepeatingSql(this.lookupPrimaryKeysWhereClause, findNow.size()); String sql = computeRepeatingSql(this.lookupPrimaryKeysWhereClause, findNow.size());
@ -267,7 +263,7 @@ public class BasicLookupStrategy implements LookupStrategy {
* automatically create entries if required) * automatically create entries if required)
*/ */
@Override @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.isTrue(this.batchSize >= 1, "BatchSize must be >= 1");
Assert.notEmpty(objects, "Objects to lookup required"); Assert.notEmpty(objects, "Objects to lookup required");
// Map<ObjectIdentity,Acl> // Map<ObjectIdentity,Acl>
@ -326,7 +322,7 @@ public class BasicLookupStrategy implements LookupStrategy {
* properly-configured parent ACLs. * properly-configured parent ACLs.
*/ */
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities, private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities,
@Nullable List<Sid> sids) { List<Sid> sids) {
Assert.notEmpty(objectIdentities, "Must provide identities to lookup"); Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
// contains Acls with StubAclParents // contains Acls with StubAclParents
@ -402,10 +398,8 @@ public class BasicLookupStrategy implements LookupStrategy {
} }
// Now we have the parent (if there is one), create the true AclImpl // 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, 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 // Copy the "aces" from the input to the destination
@ -511,9 +505,9 @@ public class BasicLookupStrategy implements LookupStrategy {
private final Map<Serializable, Acl> acls; 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"); Assert.notNull(acls, "ACLs cannot be null");
this.acls = acls; this.acls = acls;
this.sids = sids; // can be null this.sids = sids; // can be null
@ -584,9 +578,6 @@ public class BasicLookupStrategy implements LookupStrategy {
// target id type, e.g. UUID. // target id type, e.g. UUID.
Serializable identifier = (Serializable) rs.getObject("object_id_identity"); Serializable identifier = (Serializable) rs.getObject("object_id_identity");
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs); identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
if (identifier == null) {
throw new IllegalStateException("Identifier cannot be null");
}
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
.createObjectIdentity(identifier, rs.getString("class")); .createObjectIdentity(identifier, rs.getString("class"));
@ -678,7 +669,7 @@ public class BasicLookupStrategy implements LookupStrategy {
} }
@Override @Override
public boolean isSidLoaded(@Nullable List<Sid> sids) { public boolean isSidLoaded(List<Sid> sids) {
throw new UnsupportedOperationException("Stub only"); throw new UnsupportedOperationException("Stub only");
} }

View File

@ -27,7 +27,6 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcOperations;
@ -99,7 +98,7 @@ public class JdbcAclService implements AclService {
} }
@Override @Override
public @Nullable List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) { public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() }; Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql,
(rs, rowNum) -> mapObjectIdentityRow(rs), args); (rs, rowNum) -> mapObjectIdentityRow(rs), args);
@ -110,14 +109,11 @@ public class JdbcAclService implements AclService {
String javaType = rs.getString("class"); String javaType = rs.getString("class");
Serializable identifier = (Serializable) rs.getObject("obj_id"); Serializable identifier = (Serializable) rs.getObject("obj_id");
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs); identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
if (identifier == null) {
throw new IllegalStateException("Identifier cannot be null");
}
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType); return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
} }
@Override @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); Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
Assert.isTrue(map.containsKey(object), Assert.isTrue(map.containsKey(object),
() -> "There should have been an Acl entry for ObjectIdentity " + object); () -> "There should have been an Acl entry for ObjectIdentity " + object);
@ -135,7 +131,7 @@ public class JdbcAclService implements AclService {
} }
@Override @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 { throws NotFoundException {
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids); Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
// Check every requested object identity was found (throw NotFoundException if // Check every requested object identity was found (throw NotFoundException if
@ -164,7 +160,7 @@ public class JdbcAclService implements AclService {
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE; this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
} }
else { else {
log.debug("Find children statement has already been overridden, so not overriding the default"); log.debug("Find children statement has already been overridden, so not overridding the default");
} }
} }
} }

View File

@ -22,8 +22,6 @@ import java.util.List;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.security.acls.domain.AccessControlEntryImpl; import org.springframework.security.acls.domain.AccessControlEntryImpl;
@ -52,7 +50,7 @@ import org.springframework.util.Assert;
* The default settings are for HSQLDB. If you are using a different database you will * The default settings are for HSQLDB. If you are using a different database you will
* probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and * probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The * {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The
* other queries, SQL inserts and updates can also be customized to accommodate schema * other queries, SQL inserts and updates can also be customized to accomodate schema
* variations, but must produce results consistent with those expected by the defaults. * variations, but must produce results consistent with those expected by the defaults.
* <p> * <p>
* See the appendix of the Spring Security reference manual for more information on the * See the appendix of the Spring Security reference manual for more information on the
@ -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 // Need to retrieve the current principal, in order to know who "owns" this ACL
// (can be changed later on) // (can be changed later on)
Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication(); Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
Assert.isTrue(auth != null, "Authentication required");
PrincipalSid sid = new PrincipalSid(auth); PrincipalSid sid = new PrincipalSid(auth);
// Create the acl_object_identity row // 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"); Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_; AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
Assert.state(acl.getId() != null, "ACL ID cannot be null");
stmt.setLong(1, (Long) acl.getId()); stmt.setLong(1, (Long) acl.getId());
stmt.setInt(2, i); stmt.setInt(2, i);
Long sidPrimaryKey = createOrRetrieveSidPrimaryKey(entry.getSid(), true); stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true));
Assert.state(sidPrimaryKey != null, "SID primary key cannot be null");
stmt.setLong(3, sidPrimaryKey);
stmt.setInt(4, entry.getPermission().getMask()); stmt.setInt(4, entry.getPermission().getMask());
stmt.setBoolean(5, entry.isGranting()); stmt.setBoolean(5, entry.isGranting());
stmt.setBoolean(6, entry.isAuditSuccess()); 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 * @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found * @return the primary key or null if not found
*/ */
protected @Nullable Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) { protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
List<@Nullable Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type); List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
if (!classIds.isEmpty()) { if (!classIds.isEmpty()) {
Long result = classIds.get(0); return classIds.get(0);
if (result != null) {
return result;
}
} }
if (allowCreate) { if (allowCreate) {
@ -213,9 +204,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName()); this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName());
} }
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running"); Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
Long result = this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class); return this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
Assert.state(result != null, "Failed to retrieve class primary key");
return result;
} }
return null; return null;
@ -230,7 +219,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized * @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized
* implementation. * implementation.
*/ */
protected @Nullable Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) { protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required"); Assert.notNull(sid, "Sid required");
if (sid instanceof PrincipalSid) { if (sid instanceof PrincipalSid) {
String sidName = ((PrincipalSid) sid).getPrincipal(); 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 * @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found * @return the primary key or null if not found
*/ */
protected @Nullable Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
boolean allowCreate) { List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidIsPrincipal,
List<@Nullable Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidName);
sidIsPrincipal, sidName);
if (!sidIds.isEmpty()) { if (!sidIds.isEmpty()) {
Long result = sidIds.get(0); return sidIds.get(0);
if (result != null) {
return result;
}
} }
if (allowCreate) { if (allowCreate) {
this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName); this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName);
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running"); Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
Long result = this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class); return this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
Assert.state(result != null, "Failed to retrieve sid primary key");
return result;
} }
return null; return null;
} }
@ -296,9 +279,6 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
} }
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity); 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 // Delete this ACL's ACEs in the acl_entry table
deleteEntries(oidPrimaryKey); deleteEntries(oidPrimaryKey);
@ -339,11 +319,10 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
* @param oid to find * @param oid to find
* @return the object identity or null if not found * @return the object identity or null if not found
*/ */
protected @Nullable Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) { protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try { try {
Long result = this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, return this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, oid.getType(),
oid.getType(), oid.getIdentifier().toString()); oid.getIdentifier().toString());
return result;
} }
catch (DataAccessException notFound) { catch (DataAccessException notFound) {
return null; return null;
@ -361,11 +340,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier"); Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
// Delete this ACL's ACEs in the acl_entry table // Delete this ACL's ACEs in the acl_entry table
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()); deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
if (oidPrimaryKey == null) {
throw new NotFoundException("Object identity not found for ACL: " + acl.getObjectIdentity());
}
deleteEntries(oidPrimaryKey);
// Create this ACL's ACEs in the acl_entry table // Create this ACL's ACEs in the acl_entry table
createEntries(acl); createEntries(acl);
@ -496,7 +471,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
this.insertClass = DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID; this.insertClass = DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID;
} }
else { else {
log.debug("Insert class statement has already been overridden, so not overriding the default"); log.debug("Insert class statement has already been overridden, so not overridding the default");
} }
} }
} }

View File

@ -19,8 +19,6 @@ package org.springframework.security.acls.jdbc;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.security.acls.model.Acl; import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.NotFoundException; import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity; 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 * {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used to
* automatically create entries if required) * 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);
} }

View File

@ -17,7 +17,4 @@
/** /**
* JDBC-based persistence of ACL information * JDBC-based persistence of ACL information
*/ */
@NullMarked
package org.springframework.security.acls.jdbc; package org.springframework.security.acls.jdbc;
import org.jspecify.annotations.NullMarked;

View File

@ -18,8 +18,6 @@ package org.springframework.security.acls.model;
import java.io.Serializable; import java.io.Serializable;
import org.jspecify.annotations.Nullable;
/** /**
* Represents an individual permission assignment within an {@link Acl}. * 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. * Obtains an identifier that represents this ACE.
* @return the identifier, or <code>null</code> if unsaved * @return the identifier, or <code>null</code> if unsaved
*/ */
@Nullable Serializable getId(); Serializable getId();
Permission getPermission(); Permission getPermission();

View File

@ -19,8 +19,6 @@ package org.springframework.security.acls.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import org.jspecify.annotations.Nullable;
/** /**
* Represents an access control list (ACL) for a domain object. * 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 * @return the owner (may be <tt>null</tt> if the implementation does not use
* ownership concepts) * ownership concepts)
*/ */
@Nullable Sid getOwner(); Sid getOwner();
/** /**
* A domain object may have a parent for the purpose of ACL inheritance. If there is a * 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 * @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not
* have a parent) * have a parent)
*/ */
@Nullable Acl getParentAcl(); Acl getParentAcl();
/** /**
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down * 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 * @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this
* <tt>Acl</tt> instance * <tt>Acl</tt> instance
*/ */
boolean isSidLoaded(@Nullable List<Sid> sids); boolean isSidLoaded(List<Sid> sids);
} }

View File

@ -18,8 +18,6 @@ package org.springframework.security.acls.model;
import java.io.Serializable; import java.io.Serializable;
import org.jspecify.annotations.Nullable;
import org.springframework.security.acls.jdbc.JdbcAclService; import org.springframework.security.acls.jdbc.JdbcAclService;
/** /**
@ -33,9 +31,9 @@ public interface AclCache {
void evictFromCache(ObjectIdentity objectIdentity); 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); void putInCache(MutableAcl acl);

View File

@ -19,8 +19,6 @@ package org.springframework.security.acls.model;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
/** /**
* Provides retrieval of {@link Acl} instances. * Provides retrieval of {@link Acl} instances.
* *
@ -34,7 +32,7 @@ public interface AclService {
* @param parentIdentity to locate children of * @param parentIdentity to locate children of
* @return the children (or <tt>null</tt> if none were found) * @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. * 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 * @throws NotFoundException if an {@link Acl} was not found for the requested
* {@link ObjectIdentity} * {@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. * 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 * @throws NotFoundException if an {@link Acl} was not found for each requested
* {@link ObjectIdentity} * {@link ObjectIdentity}
*/ */
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, @Nullable List<Sid> sids) Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
throws NotFoundException;
} }

View File

@ -18,7 +18,4 @@
* Interfaces and shared classes to manage access control lists (ACLs) for domain object * Interfaces and shared classes to manage access control lists (ACLs) for domain object
* instances. * instances.
*/ */
@NullMarked
package org.springframework.security.acls.model; package org.springframework.security.acls.model;
import org.jspecify.annotations.NullMarked;

View File

@ -24,7 +24,4 @@
* older and more verbose attribute/voter/after-invocation approach from versions before * older and more verbose attribute/voter/after-invocation approach from versions before
* Spring Security 3.0. * Spring Security 3.0.
*/ */
@NullMarked
package org.springframework.security.acls; package org.springframework.security.acls;
import org.jspecify.annotations.NullMarked;

View File

@ -1,2 +0,0 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
org.springframework.security.acls.aot.hint.AclRuntimeHints

View File

@ -478,7 +478,6 @@ public class AclImplTests {
} }
@Test @Test
@SuppressWarnings("unchecked")
public void hashCodeWithoutStackOverFlow() throws Exception { public void hashCodeWithoutStackOverFlow() throws Exception {
Sid sid = new PrincipalSid("pSid"); Sid sid = new PrincipalSid("pSid");
ObjectIdentity oid = new ObjectIdentityImpl("type", 1); ObjectIdentity oid = new ObjectIdentityImpl("type", 1);

View File

@ -29,7 +29,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 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.anyList;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@ -109,8 +109,7 @@ public class JdbcAclServiceTests {
List<ObjectIdentity> result = new ArrayList<>(); List<ObjectIdentity> result = new ArrayList<>();
result.add(new ObjectIdentityImpl(Object.class, "5577")); result.add(new ObjectIdentityImpl(Object.class, "5577"));
Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" }; Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" };
given(this.jdbcOperations.query(anyString(), ArgumentMatchers.<RowMapper<ObjectIdentity>>any(), eq(args))) given(this.jdbcOperations.query(anyString(), any(RowMapper.class), eq(args))).willReturn(result);
.willReturn(result);
ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L); ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L);
List<ObjectIdentity> objectIdentities = this.aclService.findChildren(objectIdentity); List<ObjectIdentity> objectIdentities = this.aclService.findChildren(objectIdentity);
assertThat(objectIdentities).hasSize(1); assertThat(objectIdentities).hasSize(1);

View File

@ -80,10 +80,11 @@ public class SpringCacheBasedAclCacheTests {
assertThatIllegalArgumentException().isThrownBy(() -> new SpringCacheBasedAclCache(null, null, null)); assertThatIllegalArgumentException().isThrownBy(() -> new SpringCacheBasedAclCache(null, null, null));
} }
@SuppressWarnings("rawtypes")
@Test @Test
public void cacheOperationsAclWithoutParent() { public void cacheOperationsAclWithoutParent() {
Cache cache = getCache(); Cache cache = getCache();
Map<?, ?> realCache = (Map<?, ?>) cache.getNativeCache(); Map realCache = (Map) cache.getNativeCache();
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100L); ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100L);
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl( AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"), new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
@ -115,10 +116,11 @@ public class SpringCacheBasedAclCacheTests {
assertThat(realCache).isEmpty(); assertThat(realCache).isEmpty();
} }
@SuppressWarnings("rawtypes")
@Test @Test
public void cacheOperationsAclWithParent() throws Exception { public void cacheOperationsAclWithParent() throws Exception {
Cache cache = getCache(); Cache cache = getCache();
Map<?, ?> realCache = (Map<?, ?>) cache.getNativeCache(); Map realCache = (Map) cache.getNativeCache();
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL"); Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
auth.setAuthenticated(true); auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth); SecurityContextHolder.getContext().setAuthentication(auth);

View File

@ -1,17 +1,13 @@
apply plugin: 'io.spring.convention.spring-module' apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'io.freefair.aspectj' apply plugin: 'io.freefair.aspectj'
apply plugin: 'javadoc-warnings-error'
apply plugin: 'compile-warnings-error'
compileAspectj { compileAspectj {
sourceCompatibility = "17" sourceCompatibility "17"
targetCompatibility = "17" targetCompatibility "17"
ajcOptions.compilerArgs += ['-Xlint:ignore']
} }
compileTestAspectj { compileTestAspectj {
sourceCompatibility = "17" sourceCompatibility "17"
targetCompatibility = "17" targetCompatibility "17"
ajcOptions.compilerArgs += ['-Xlint:ignore']
} }
dependencies { dependencies {
@ -22,8 +18,6 @@ dependencies {
api 'org.springframework:spring-context' api 'org.springframework:spring-context'
api 'org.springframework:spring-core' api 'org.springframework:spring-core'
optional project(':spring-security-access')
testImplementation 'org.springframework:spring-aop' testImplementation 'org.springframework:spring-aop'
testImplementation "org.assertj:assertj-core" testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api" testImplementation "org.junit.jupiter:junit-jupiter-api"

View File

@ -1,7 +1,6 @@
import io.spring.gradle.convention.SpringModulePlugin import io.spring.gradle.convention.SpringModulePlugin
apply plugin: 'io.spring.convention.bom' apply plugin: 'io.spring.convention.bom'
apply plugin: 'compile-warnings-error'
dependencies { dependencies {
constraints { constraints {

View File

@ -1,7 +1,5 @@
import io.spring.gradle.IncludeRepoTask import io.spring.gradle.IncludeRepoTask
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import trang.RncToXsd import trang.RncToXsd
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
buildscript { buildscript {
dependencies { dependencies {
@ -12,7 +10,7 @@ buildscript {
classpath libs.com.netflix.nebula.nebula.project.plugin classpath libs.com.netflix.nebula.nebula.project.plugin
} }
repositories { repositories {
maven { url='https://plugins.gradle.org/m2/' } maven { url 'https://plugins.gradle.org/m2/' }
} }
} }
@ -37,7 +35,7 @@ ext.milestoneBuild = !(snapshotBuild || releaseBuild)
repositories { repositories {
mavenCentral() mavenCentral()
maven { url = "https://repo.spring.io/milestone" } maven { url "https://repo.spring.io/milestone" }
} }
springRelease { springRelease {
@ -48,19 +46,46 @@ springRelease {
replaceSnapshotVersionInReferenceDocUrl = true replaceSnapshotVersionInReferenceDocUrl = true
} }
def toolchainVersion() {
if (project.hasProperty('testToolchain')) {
return project.property('testToolchain').toString().toInteger()
}
return 17
}
subprojects {
java {
toolchain {
languageVersion = JavaLanguageVersion.of(toolchainVersion())
}
}
kotlin {
jvmToolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
options.release.set(17)
}
}
allprojects { allprojects {
if (!['spring-security-bom', 'spring-security-docs'].contains(project.name)) { if (!['spring-security-bom', 'spring-security-docs'].contains(project.name)) {
apply plugin: 'io.spring.javaformat' apply plugin: 'io.spring.javaformat'
apply plugin: 'checkstyle' apply plugin: 'checkstyle'
pluginManager.withPlugin("io.spring.convention.checkstyle") { pluginManager.withPlugin("io.spring.convention.checkstyle", { plugin ->
dependencies { configure(plugin) {
checkstyle libs.io.spring.javaformat.spring.javaformat.checkstyle dependencies {
checkstyle libs.io.spring.javaformat.spring.javaformat.checkstyle
}
checkstyle {
toolVersion = '8.34'
}
} }
checkstyle { })
toolVersion = '8.34'
}
}
if (project.name.contains('sample')) { if (project.name.contains('sample')) {
tasks.whenTaskAdded { task -> tasks.whenTaskAdded { task ->

View File

@ -1,6 +1,5 @@
plugins { plugins {
id "java-gradle-plugin" id "java-gradle-plugin"
id "groovy-gradle-plugin"
id "java" id "java"
id "groovy" id "groovy"
} }
@ -12,7 +11,7 @@ java {
repositories { repositories {
gradlePluginPortal() gradlePluginPortal()
mavenCentral() mavenCentral()
maven { url = 'https://repo.spring.io/snapshot' } maven { url 'https://repo.spring.io/milestone' }
} }
sourceSets { sourceSets {
@ -64,7 +63,6 @@ configurations {
dependencies { dependencies {
implementation platform(libs.io.projectreactor.reactor.bom) implementation platform(libs.io.projectreactor.reactor.bom)
implementation libs.spring.nullability
implementation libs.com.google.code.gson.gson implementation libs.com.google.code.gson.gson
implementation libs.com.thaiopensource.trag implementation libs.com.thaiopensource.trag
implementation libs.net.sourceforge.saxon.saxon implementation libs.net.sourceforge.saxon.saxon
@ -78,7 +76,6 @@ dependencies {
implementation libs.com.github.spullara.mustache.java.compiler implementation libs.com.github.spullara.mustache.java.compiler
implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin
implementation libs.io.spring.nohttp.nohttp.gradle implementation libs.io.spring.nohttp.nohttp.gradle
implementation libs.org.jetbrains.kotlin.kotlin.gradle.plugin
implementation (libs.net.sourceforge.htmlunit) { implementation (libs.net.sourceforge.htmlunit) {
exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client' exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client'
} }

View File

@ -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
}

View File

@ -81,8 +81,8 @@ class ArtifactoryPlugin implements Plugin<Project> {
repository { repository {
repoKey = isSnapshot ? snapshotRepository : isMilestone ? milestoneRepository : releaseRepository repoKey = isSnapshot ? snapshotRepository : isMilestone ? milestoneRepository : releaseRepository
if(project.hasProperty('artifactoryUsername')) { if(project.hasProperty('artifactoryUsername')) {
username = project.artifactoryUsername username = artifactoryUsername
password = project.artifactoryPassword password = artifactoryPassword
} }
} }
} }

View File

@ -31,12 +31,12 @@ public class DocsPlugin implements Plugin<Project> {
into 'api' into 'api'
} }
into 'docs' into 'docs'
duplicatesStrategy = 'exclude' duplicatesStrategy 'exclude'
} }
Task docs = project.tasks.create("docs") { Task docs = project.tasks.create("docs") {
group = 'Documentation' group = 'Documentation'
description = 'An aggregator task to generate all the documentation' description 'An aggregator task to generate all the documentation'
dependsOn docsZip dependsOn docsZip
} }
project.tasks.assemble.dependsOn docs project.tasks.assemble.dependsOn docs

View File

@ -90,7 +90,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.plugins.withType(IdeaPlugin) { project.plugins.withType(IdeaPlugin) {
project.idea { project.idea {
module { module {
testSources.from(project.file('src/integration-test/java')) testSourceDirs += project.file('src/integration-test/java')
scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ] scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ]
} }
} }
@ -105,7 +105,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.plugins.withType(IdeaPlugin) { project.plugins.withType(IdeaPlugin) {
project.idea { project.idea {
module { module {
testSources.from(project.file('src/integration-test/groovy')) testSourceDirs += project.file('src/integration-test/groovy')
} }
} }
} }

View File

@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin<Project> {
project.tasks.check.dependsOn project.tasks.jacocoTestReport project.tasks.check.dependsOn project.tasks.jacocoTestReport
project.jacoco { project.jacoco {
toolVersion = '0.8.14' toolVersion = '0.8.9'
} }
} }
} }

View File

@ -26,7 +26,7 @@ import org.gradle.api.Action;
import org.gradle.api.JavaVersion import org.gradle.api.JavaVersion
import org.gradle.api.Plugin; import org.gradle.api.Plugin;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.javadoc.Javadoc; import org.gradle.api.tasks.javadoc.Javadoc;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -71,7 +71,7 @@ public class JavadocApiPlugin implements Plugin<Project> {
} }
api.setMaxMemory("1024m"); api.setMaxMemory("1024m");
api.setDestinationDir(project.layout.getBuildDirectory().dir("api").get().getAsFile()); api.setDestinationDir(new File(project.getBuildDir(), "api"));
project.getPluginManager().apply("io.spring.convention.javadoc-options"); project.getPluginManager().apply("io.spring.convention.javadoc-options");
} }
@ -99,7 +99,7 @@ public class JavadocApiPlugin implements Plugin<Project> {
public void execute(SpringModulePlugin plugin) { public void execute(SpringModulePlugin plugin) {
logger.info("Added sources for {}", project); logger.info("Added sources for {}", project);
JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension.class); JavaPluginConvention java = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet mainSourceSet = java.getSourceSets().getByName("main"); SourceSet mainSourceSet = java.getSourceSets().getByName("main");
api.setSource(api.getSource().plus(mainSourceSet.getAllJava())); api.setSource(api.getSource().plus(mainSourceSet.getAllJava()));

View File

@ -61,7 +61,7 @@ public class ManagementConfigurationPlugin implements Plugin<Project> {
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
publishing.getPublications().withType(MavenPublication.class, (mavenPublication -> { publishing.getPublications().withType(MavenPublication.class, (mavenPublication -> {
mavenPublication.versionMapping((versions) -> mavenPublication.versionMapping((versions) ->
versions.allVariants((versionMapping) -> versionMapping.fromResolutionResult()) versions.allVariants(versionMapping -> versionMapping.fromResolutionResult())
); );
})); }));
}); });

View File

@ -80,11 +80,6 @@ class RepositoryConventionPlugin implements Plugin<Project> {
} }
url = 'https://repo.spring.io/release/' url = 'https://repo.spring.io/release/'
} }
forceMavenRepositories.findAll { it.startsWith('https://') || it.startsWith('file://') }.each { mavenUrl ->
maven {
url mavenUrl
}
}
} }
} }

View File

@ -32,15 +32,12 @@ public class SchemaZipPlugin implements Plugin<Project> {
for (def key : schemas.keySet()) { for (def key : schemas.keySet()) {
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
assert shortName != key assert shortName != key
def schemaResourceName = schemas.get(key)
File xsdFile = module.sourceSets.main.resources.find { File xsdFile = module.sourceSets.main.resources.find {
it.path.endsWith(schemaResourceName) it.path.endsWith(schemas.get(key))
}
if (xsdFile == null) {
throw new IllegalStateException("Could not find schema file for resource name " + schemaResourceName + " in src/main/resources")
} }
assert xsdFile != null
schemaZip.into (shortName) { schemaZip.into (shortName) {
duplicatesStrategy = 'exclude' duplicatesStrategy 'exclude'
from xsdFile.path from xsdFile.path
} }
versionlessXsd.getInputFiles().from(xsdFile.path) versionlessXsd.getInputFiles().from(xsdFile.path)

View File

@ -35,7 +35,6 @@ class SpringModulePlugin extends AbstractSpringJavaPlugin {
pluginManager.apply(SpringMavenPlugin.class); pluginManager.apply(SpringMavenPlugin.class);
pluginManager.apply(CheckClasspathForProhibitedDependenciesPlugin.class); pluginManager.apply(CheckClasspathForProhibitedDependenciesPlugin.class);
pluginManager.apply("io.spring.convention.jacoco"); pluginManager.apply("io.spring.convention.jacoco");
pluginManager.apply("java-toolchain");
def deployArtifacts = project.task("deployArtifacts") def deployArtifacts = project.task("deployArtifacts")
deployArtifacts.group = 'Deploy tasks' deployArtifacts.group = 'Deploy tasks'

View File

@ -1,36 +0,0 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
def toolchainVersion() {
if (project.hasProperty('testToolchain')) {
return project.property('testToolchain').toString().toInteger()
}
return 25
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(toolchainVersion())
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
options.release = 17
}
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
kotlin {
jvmToolchain {
languageVersion = JavaLanguageVersion.of(toolchainVersion())
}
}
tasks.withType(KotlinCompile).configureEach {
compilerOptions {
javaParameters = true
jvmTarget.set(JvmTarget.JVM_17)
}
}
}

View File

@ -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')
}

View File

@ -1,17 +0,0 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id 'kotlin'
}
project.plugins.withId("org.jetbrains.kotlin.jvm", (kotlinProject) -> {
project.tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
languageVersion = '2.2'
apiVersion = '2.2'
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
jvmTarget = '17'
}
}
})

View File

@ -1,3 +0,0 @@
plugins {
id 'io.spring.nullability'
}

View File

@ -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'
}
}

View File

@ -81,6 +81,9 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask {
if (group.startsWith("javax")) { if (group.startsWith("javax")) {
return true; return true;
} }
if (group.equals("commons-logging")) {
return true;
}
if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) { if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
return true; return true;
} }

View File

@ -46,7 +46,7 @@ public class CheckExpectedBranchVersionPlugin implements Plugin<Project> {
task.setDescription("Check if the project version matches the branch version"); task.setDescription("Check if the project version matches the branch version");
task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent); task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent);
task.getVersion().convention(project.provider(() -> project.getVersion().toString())); task.getVersion().convention(project.provider(() -> project.getVersion().toString()));
task.getBranchName().convention(project.getProviders().exec((execSpec) -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText()); task.getBranchName().convention(project.getProviders().exec(execSpec -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText());
task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version")); task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version"));
}); });
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask)); project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask));

View File

@ -83,8 +83,12 @@ public class VerifyDependenciesVersionsPlugin implements Plugin<Project> {
String transitiveNimbusJoseJwtVersion = TransitiveDependencyLookupUtils.lookupJwtVersion(oauth2OidcSdkVersion); String transitiveNimbusJoseJwtVersion = TransitiveDependencyLookupUtils.lookupJwtVersion(oauth2OidcSdkVersion);
String expectedNimbusJoseJwtVersion = this.getExpectedNimbusJoseJwtVersion().get(); String expectedNimbusJoseJwtVersion = this.getExpectedNimbusJoseJwtVersion().get();
if (!transitiveNimbusJoseJwtVersion.equals(expectedNimbusJoseJwtVersion)) { if (!transitiveNimbusJoseJwtVersion.equals(expectedNimbusJoseJwtVersion)) {
String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, but the project contains a different version of nimbus-jose-jwt [%s]. Please align the versions.", transitiveNimbusJoseJwtVersion, oauth2OidcSdkVersion, expectedNimbusJoseJwtVersion); String transitiveNimbusJoseJwtMajorMinorVersion = transitiveNimbusJoseJwtVersion.substring(0, transitiveNimbusJoseJwtVersion.lastIndexOf("."));
throw new VerificationException(message); String expectedNimbusJoseJwtMajorMinorVersion = expectedNimbusJoseJwtVersion.substring(0, expectedNimbusJoseJwtVersion.lastIndexOf("."));
if (!transitiveNimbusJoseJwtMajorMinorVersion.equals(expectedNimbusJoseJwtMajorMinorVersion)) {
String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, but the project contains a different version of nimbus-jose-jwt [%s]. Please align the major/minor versions.", transitiveNimbusJoseJwtVersion, oauth2OidcSdkVersion, expectedNimbusJoseJwtVersion);
throw new VerificationException(message);
}
} }
String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, the project contains expected version of nimbus-jose-jwt [%s]. Verified all versions align.", transitiveNimbusJoseJwtVersion, oauth2OidcSdkVersion, expectedNimbusJoseJwtVersion); String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, the project contains expected version of nimbus-jose-jwt [%s]. Verified all versions align.", transitiveNimbusJoseJwtVersion, oauth2OidcSdkVersion, expectedNimbusJoseJwtVersion);
try { try {

View File

@ -17,6 +17,8 @@ package io.spring.gradle;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.gradle.testkit.runner.GradleRunner; import org.gradle.testkit.runner.GradleRunner;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@ -23,6 +23,8 @@ import org.gradle.testfixtures.ProjectBuilder;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.File;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**

View File

@ -5,6 +5,7 @@ import org.apache.commons.io.FileUtils;
import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome; import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;

View File

@ -1,9 +1,3 @@
plugins {
id 'security-nullability'
id 'javadoc-warnings-error'
id 'compile-warnings-error'
}
apply plugin: 'io.spring.convention.spring-module' apply plugin: 'io.spring.convention.spring-module'
dependencies { dependencies {
@ -17,11 +11,9 @@ dependencies {
api 'org.springframework:spring-web' api 'org.springframework:spring-web'
optional 'com.fasterxml.jackson.core:jackson-databind' optional 'com.fasterxml.jackson.core:jackson-databind'
optional 'tools.jackson.core:jackson-databind'
provided 'jakarta.servlet:jakarta.servlet-api' provided 'jakarta.servlet:jakarta.servlet-api'
testImplementation project(path : ':spring-security-web', configuration : 'tests')
testImplementation "org.assertj:assertj-core" testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api" testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params" testImplementation "org.junit.jupiter:junit-jupiter-params"

View File

@ -16,8 +16,6 @@
package org.springframework.security.cas; package org.springframework.security.cas;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -36,7 +34,7 @@ public class ServiceProperties implements InitializingBean {
public static final String DEFAULT_CAS_SERVICE_PARAMETER = "service"; public static final String DEFAULT_CAS_SERVICE_PARAMETER = "service";
private @Nullable String service; private String service;
private boolean authenticateAllArtifacts; private boolean authenticateAllArtifacts;
@ -64,7 +62,7 @@ public class ServiceProperties implements InitializingBean {
* </pre> * </pre>
* @return the URL of the service the user is authenticating to * @return the URL of the service the user is authenticating to
*/ */
public final @Nullable String getService() { public final String getService() {
return this.service; return this.service;
} }

View File

@ -21,6 +21,7 @@ import java.util.ArrayList;
import org.apereo.cas.client.validation.Assertion; import org.apereo.cas.client.validation.Assertion;
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.SpringSecurityCoreVersion;
/** /**
* Temporary authentication object needed to load the user details service. * Temporary authentication object needed to load the user details service.
@ -30,7 +31,7 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
*/ */
public final class CasAssertionAuthenticationToken extends AbstractAuthenticationToken { public final class CasAssertionAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 620L; private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final Assertion assertion; private final Assertion assertion;

View File

@ -16,15 +16,11 @@
package org.springframework.security.cas.authentication; package org.springframework.security.cas.authentication;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apereo.cas.client.validation.Assertion; import org.apereo.cas.client.validation.Assertion;
import org.apereo.cas.client.validation.TicketValidationException; import org.apereo.cas.client.validation.TicketValidationException;
import org.apereo.cas.client.validation.TicketValidator; import org.apereo.cas.client.validation.TicketValidator;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
@ -37,9 +33,7 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.cas.ServiceProperties; import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.FactorGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
@ -68,9 +62,6 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class); private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
private static final String AUTHORITY = FactorGrantedAuthority.CAS_AUTHORITY;
@SuppressWarnings("NullAway.Init")
private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService; private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService;
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker(); private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
@ -79,13 +70,11 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache(); private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
@SuppressWarnings("NullAway.Init")
private String key; private String key;
@SuppressWarnings("NullAway.Init")
private TicketValidator ticketValidator; private TicketValidator ticketValidator;
private @Nullable ServiceProperties serviceProperties; private ServiceProperties serviceProperties;
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
@ -100,7 +89,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
} }
@Override @Override
public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException { public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) { if (!supports(authentication.getClass())) {
return null; return null;
} }
@ -140,17 +129,12 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
private CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException { private CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {
try { try {
Object credentials = authentication.getCredentials(); Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(),
if (credentials == null) { getServiceUrl(authentication));
throw new BadCredentialsException("Authentication.getCredentials() cannot be null");
}
Assertion assertion = this.ticketValidator.validate(credentials.toString(), getServiceUrl(authentication));
UserDetails userDetails = loadUserByAssertion(assertion); UserDetails userDetails = loadUserByAssertion(assertion);
this.userDetailsChecker.check(userDetails); this.userDetailsChecker.check(userDetails);
Collection<GrantedAuthority> authorities = new ArrayList<>( return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
this.authoritiesMapper.mapAuthorities(userDetails.getAuthorities())); this.authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
authorities.add(FactorGrantedAuthority.fromAuthority(AUTHORITY));
return new CasAuthenticationToken(this.key, userDetails, credentials, authorities, userDetails, assertion);
} }
catch (TicketValidationException ex) { catch (TicketValidationException ex) {
throw new BadCredentialsException(ex.getMessage(), ex); throw new BadCredentialsException(ex.getMessage(), ex);
@ -165,7 +149,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
* @param authentication * @param authentication
* @return * @return
*/ */
private @Nullable String getServiceUrl(Authentication authentication) { private String getServiceUrl(Authentication authentication) {
String serviceUrl; String serviceUrl;
if (authentication.getDetails() instanceof ServiceAuthenticationDetails) { if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {
return ((ServiceAuthenticationDetails) authentication.getDetails()).getServiceUrl(); return ((ServiceAuthenticationDetails) authentication.getDetails()).getServiceUrl();
@ -231,7 +215,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
return this.statelessTicketCache; return this.statelessTicketCache;
} }
protected @Nullable TicketValidator getTicketValidator() { protected TicketValidator getTicketValidator() {
return this.ticketValidator; return this.ticketValidator;
} }

View File

@ -20,10 +20,10 @@ import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import org.apereo.cas.client.validation.Assertion; import org.apereo.cas.client.validation.Assertion;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@ -36,7 +36,7 @@ import org.springframework.util.ObjectUtils;
*/ */
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable { public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
private static final long serialVersionUID = 620L; private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final Object credentials; private final Object credentials;
@ -105,19 +105,6 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
setAuthenticated(true); setAuthenticated(true);
} }
protected CasAuthenticationToken(Builder<?> builder) {
super(builder);
Assert.isTrue(!"".equals(builder.principal), "principal cannot be null or empty");
Assert.notNull(!"".equals(builder.credentials), "credentials cannot be null or empty");
Assert.notNull(builder.userDetails, "userDetails cannot be null");
Assert.notNull(builder.assertion, "assertion cannot be null");
this.keyHash = builder.keyHash;
this.principal = builder.principal;
this.credentials = builder.credentials;
this.userDetails = builder.userDetails;
this.assertion = builder.assertion;
}
private static Integer extractKeyHash(String key) { private static Integer extractKeyHash(String key) {
Assert.hasLength(key, "key cannot be null or empty"); Assert.hasLength(key, "key cannot be null or empty");
return key.hashCode(); return key.hashCode();
@ -167,11 +154,6 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
return this.userDetails; return this.userDetails;
} }
@Override
public Builder<?> toBuilder() {
return new Builder<>(this);
}
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -181,81 +163,4 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
return (sb.toString()); return (sb.toString());
} }
/**
* A builder of {@link CasAuthenticationToken} instances
*
* @since 7.0
*/
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<B> {
private Integer keyHash;
private Object principal;
private Object credentials;
private UserDetails userDetails;
private Assertion assertion;
protected Builder(CasAuthenticationToken token) {
super(token);
this.keyHash = token.keyHash;
this.principal = token.principal;
this.credentials = token.credentials;
this.userDetails = token.userDetails;
this.assertion = token.assertion;
}
/**
* Use this key
* @param key the key to use
* @return the {@link Builder} for further configurations
*/
public B key(String key) {
this.keyHash = key.hashCode();
return (B) this;
}
@Override
public B principal(@Nullable Object principal) {
Assert.notNull(principal, "principal cannot be null");
this.principal = principal;
return (B) this;
}
@Override
public B credentials(@Nullable Object credentials) {
Assert.notNull(credentials, "credentials cannot be null");
this.credentials = credentials;
return (B) this;
}
/**
* Use this {@link UserDetails}
* @param userDetails the {@link UserDetails} to use
* @return the {@link Builder} for further configurations
*/
public B userDetails(UserDetails userDetails) {
this.userDetails = userDetails;
return (B) this;
}
/**
* Use this {@link Assertion}
* @param assertion the {@link Assertion} to use
* @return the {@link Builder} for further configurations
*/
public B assertion(Assertion assertion) {
this.assertion = assertion;
return (B) this;
}
@Override
public CasAuthenticationToken build() {
return new CasAuthenticationToken(this);
}
}
} }

View File

@ -19,10 +19,9 @@ package org.springframework.security.cas.authentication;
import java.io.Serial; import java.io.Serial;
import java.util.Collection; import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -39,11 +38,11 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_"; static final String CAS_STATEFUL_IDENTIFIER = "_cas_stateful_";
@Serial @Serial
private static final long serialVersionUID = 620L; private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final String identifier; private final String identifier;
private @Nullable Object credentials; private Object credentials;
/** /**
* This constructor can be safely used by any code that wishes to create a * This constructor can be safely used by any code that wishes to create a
@ -52,7 +51,7 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
* *
*/ */
public CasServiceTicketAuthenticationToken(String identifier, Object credentials) { public CasServiceTicketAuthenticationToken(String identifier, Object credentials) {
super((Collection<? extends GrantedAuthority>) null); super(null);
this.identifier = identifier; this.identifier = identifier;
this.credentials = credentials; this.credentials = credentials;
setAuthenticated(false); setAuthenticated(false);
@ -75,12 +74,6 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
super.setAuthenticated(true); super.setAuthenticated(true);
} }
protected CasServiceTicketAuthenticationToken(Builder<?> builder) {
super(builder);
this.identifier = builder.principal;
this.credentials = builder.credentials;
}
public static CasServiceTicketAuthenticationToken stateful(Object credentials) { public static CasServiceTicketAuthenticationToken stateful(Object credentials) {
return new CasServiceTicketAuthenticationToken(CAS_STATEFUL_IDENTIFIER, credentials); return new CasServiceTicketAuthenticationToken(CAS_STATEFUL_IDENTIFIER, credentials);
} }
@ -94,7 +87,7 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
} }
@Override @Override
public @Nullable Object getCredentials() { public Object getCredentials() {
return this.credentials; return this.credentials;
} }
@ -116,46 +109,4 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
this.credentials = null; this.credentials = null;
} }
public Builder<?> toBuilder() {
return new Builder<>(this);
}
/**
* A builder of {@link CasServiceTicketAuthenticationToken} instances
*
* @since 7.0
*/
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<B> {
private String principal;
private @Nullable Object credentials;
protected Builder(CasServiceTicketAuthenticationToken token) {
super(token);
this.principal = token.identifier;
this.credentials = token.credentials;
}
@Override
public B principal(@Nullable Object principal) {
Assert.isInstanceOf(String.class, principal, "principal must be of type String");
this.principal = (String) principal;
return (B) this;
}
@Override
public B credentials(@Nullable Object credentials) {
Assert.notNull(credentials, "credentials cannot be null");
this.credentials = credentials;
return (B) this;
}
@Override
public CasServiceTicketAuthenticationToken build() {
return new CasServiceTicketAuthenticationToken(this);
}
}
} }

View File

@ -16,8 +16,6 @@
package org.springframework.security.cas.authentication; package org.springframework.security.cas.authentication;
import org.jspecify.annotations.Nullable;
/** /**
* Implementation of @link {@link StatelessTicketCache} that has no backing cache. Useful * Implementation of @link {@link StatelessTicketCache} that has no backing cache. Useful
* in instances where storing of tickets for stateless session management is not required. * in instances where storing of tickets for stateless session management is not required.
@ -35,7 +33,7 @@ public final class NullStatelessTicketCache implements StatelessTicketCache {
* @return null since we are not storing any tickets. * @return null since we are not storing any tickets.
*/ */
@Override @Override
public @Nullable CasAuthenticationToken getByTicketId(final String serviceTicket) { public CasAuthenticationToken getByTicketId(final String serviceTicket) {
return null; return null;
} }

View File

@ -18,7 +18,6 @@ package org.springframework.security.cas.authentication;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.core.log.LogMessage; import org.springframework.core.log.LogMessage;
@ -43,7 +42,7 @@ public class SpringCacheBasedTicketCache implements StatelessTicketCache {
} }
@Override @Override
public @Nullable CasAuthenticationToken getByTicketId(final String serviceTicket) { public CasAuthenticationToken getByTicketId(final String serviceTicket) {
final Cache.ValueWrapper element = (serviceTicket != null) ? this.cache.get(serviceTicket) : null; final Cache.ValueWrapper element = (serviceTicket != null) ? this.cache.get(serviceTicket) : null;
logger.debug(LogMessage.of(() -> "Cache hit: " + (element != null) + "; service ticket: " + serviceTicket)); logger.debug(LogMessage.of(() -> "Cache hit: " + (element != null) + "; service ticket: " + serviceTicket));
return (element != null) ? (CasAuthenticationToken) element.get() : null; return (element != null) ? (CasAuthenticationToken) element.get() : null;

View File

@ -16,8 +16,6 @@
package org.springframework.security.cas.authentication; package org.springframework.security.cas.authentication;
import org.jspecify.annotations.Nullable;
/** /**
* Caches CAS service tickets and CAS proxy tickets for stateless connections. * Caches CAS service tickets and CAS proxy tickets for stateless connections.
* *
@ -71,7 +69,7 @@ public interface StatelessTicketCache {
* </p> * </p>
* @return the fully populated authentication token * @return the fully populated authentication token
*/ */
@Nullable CasAuthenticationToken getByTicketId(String serviceTicket); CasAuthenticationToken getByTicketId(String serviceTicket);
/** /**
* Adds the specified <code>CasAuthenticationToken</code> to the cache. * Adds the specified <code>CasAuthenticationToken</code> to the cache.

View File

@ -18,7 +18,4 @@
* An {@code AuthenticationProvider} that can process CAS service tickets and proxy * An {@code AuthenticationProvider} that can process CAS service tickets and proxy
* tickets. * tickets.
*/ */
@NullMarked
package org.springframework.security.cas.authentication; package org.springframework.security.cas.authentication;
import org.jspecify.annotations.NullMarked;

View File

@ -1,60 +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.cas.jackson;
import java.util.Date;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apereo.cas.client.authentication.AttributePrincipal;
/**
* Helps in jackson deserialization of class
* {@link org.apereo.cas.client.validation.AssertionImpl}, which is used with
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}.
*
* @author Sebastien Deleuze
* @author Jitendra Singh
* @since 7.0
* @see CasJacksonModule
* @see org.springframework.security.jackson.SecurityJacksonModules
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
class AssertionImplMixin {
/**
* Mixin Constructor helps in deserialize
* {@link org.apereo.cas.client.validation.AssertionImpl}
* @param principal the Principal to associate with the Assertion.
* @param validFromDate when the assertion is valid from.
* @param validUntilDate when the assertion is valid to.
* @param authenticationDate when the assertion is authenticated.
* @param attributes the key/value pairs for this attribute.
*/
@JsonCreator
AssertionImplMixin(@JsonProperty("principal") AttributePrincipal principal,
@JsonProperty("validFromDate") Date validFromDate, @JsonProperty("validUntilDate") Date validUntilDate,
@JsonProperty("authenticationDate") Date authenticationDate,
@JsonProperty("attributes") Map<String, Object> attributes) {
}
}

View File

@ -1,59 +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.cas.jackson;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apereo.cas.client.proxy.ProxyRetriever;
/**
* Helps in deserialize
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl} which is used with
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}.
*
* @author Sebastien Deleuze
* @author Jitendra Singh
* @since 7.0
* @see CasJacksonModule
* @see org.springframework.security.jackson.SecurityJacksonModules
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
class AttributePrincipalImplMixin {
/**
* Mixin Constructor helps in deserialize
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl}
* @param name the unique identifier for the principal.
* @param attributes the key/value pairs for this principal.
* @param proxyGrantingTicket the ticket associated with this principal.
* @param proxyRetriever the ProxyRetriever implementation to call back to the CAS
* server.
*/
@JsonCreator
AttributePrincipalImplMixin(@JsonProperty("name") String name,
@JsonProperty("attributes") Map<String, Object> attributes,
@JsonProperty("proxyGrantingTicket") String proxyGrantingTicket,
@JsonProperty("proxyRetriever") ProxyRetriever proxyRetriever) {
}
}

View File

@ -1,69 +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.cas.jackson;
import java.util.Collection;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apereo.cas.client.validation.Assertion;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
/**
* Mixin class which helps in deserialize {@link CasAuthenticationToken} using jackson.
*
* @author Sebastien Deleuze
* @author Jitendra Singh
* @since 7.0
* @see CasJacksonModule
* @see org.springframework.security.jackson.SecurityJacksonModules
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY)
class CasAuthenticationTokenMixin {
/**
* Mixin Constructor helps in deserialize {@link CasAuthenticationToken}
* @param keyHash hashCode of provided key to identify if this object made by a given
* {@link CasAuthenticationProvider}
* @param principal typically the UserDetails object (cannot be <code>null</code>)
* @param credentials the service/proxy ticket ID from CAS (cannot be
* <code>null</code>)
* @param authorities the authorities granted to the user (from the
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
* be <code>null</code>)
* @param userDetails the user details (from the
* {@link org.springframework.security.core.userdetails.UserDetailsService}) (cannot
* be <code>null</code>)
* @param assertion the assertion returned from the CAS servers. It contains the
* principal and how to obtain a proxy ticket for the user.
*/
@JsonCreator
CasAuthenticationTokenMixin(@JsonProperty("keyHash") Integer keyHash, @JsonProperty("principal") Object principal,
@JsonProperty("credentials") Object credentials,
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities,
@JsonProperty("userDetails") UserDetails userDetails, @JsonProperty("assertion") Assertion assertion) {
}
}

View File

@ -1,71 +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.cas.jackson;
import org.apereo.cas.client.authentication.AttributePrincipalImpl;
import org.apereo.cas.client.validation.AssertionImpl;
import tools.jackson.core.Version;
import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.jackson.SecurityJacksonModule;
import org.springframework.security.jackson.SecurityJacksonModules;
/**
* Jackson module for spring-security-cas. This module register
* {@link AssertionImplMixin}, {@link AttributePrincipalImplMixin} and
* {@link CasAuthenticationTokenMixin}. If no default typing enabled by default then it'll
* enable it because typing info is needed to properly serialize/deserialize objects. In
* order to use this module just add this module into your JsonMapper configuration.
*
* <p>
* The recommended way to configure it is to use {@link SecurityJacksonModules} in order
* to enable properly automatic inclusion of type information with related validation.
*
* <pre>
* ClassLoader loader = getClass().getClassLoader();
* JsonMapper mapper = JsonMapper.builder()
* .addModules(SecurityJacksonModules.getModules(loader))
* .build();
* </pre>
*
* @author Sebastien Deleuze
* @author Jitendra Singh
* @since 7.0
* @see SecurityJacksonModules
*/
public class CasJacksonModule extends SecurityJacksonModule {
public CasJacksonModule() {
super(CasJacksonModule.class.getName(), new Version(1, 0, 0, null, null, null));
}
@Override
public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Builder builder) {
builder.allowIfSubType(AssertionImpl.class)
.allowIfSubType(AttributePrincipalImpl.class)
.allowIfSubType(CasAuthenticationToken.class);
}
@Override
public void setupModule(SetupContext context) {
context.setMixIn(AssertionImpl.class, AssertionImplMixin.class);
context.setMixIn(AttributePrincipalImpl.class, AttributePrincipalImplMixin.class);
context.setMixIn(CasAuthenticationToken.class, CasAuthenticationTokenMixin.class);
}
}

View File

@ -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.
*/
/**
* Jackson 3+ serialization support for CAS.
*/
@NullMarked
package org.springframework.security.cas.jackson;
import org.jspecify.annotations.NullMarked;

View File

@ -33,7 +33,6 @@ import org.apereo.cas.client.authentication.AttributePrincipal;
* this class we need to register with * this class we need to register with
* {@link com.fasterxml.jackson.databind.ObjectMapper}. Type information will be stored * {@link com.fasterxml.jackson.databind.ObjectMapper}. Type information will be stored
* in @class property. * in @class property.
*
* <p> * <p>
* <pre> * <pre>
* ObjectMapper mapper = new ObjectMapper(); * ObjectMapper mapper = new ObjectMapper();
@ -44,11 +43,7 @@ import org.apereo.cas.client.authentication.AttributePrincipal;
* @since 4.2 * @since 4.2
* @see CasJackson2Module * @see CasJackson2Module
* @see org.springframework.security.jackson2.SecurityJackson2Modules * @see org.springframework.security.jackson2.SecurityJackson2Modules
* @deprecated as of 7.0 in favor of
* {@code org.springframework.security.cas.jackson.AssertionImplMixin} based on Jackson 3
*/ */
@SuppressWarnings("removal")
@Deprecated(forRemoval = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE) isGetterVisibility = JsonAutoDetect.Visibility.NONE)

View File

@ -30,7 +30,6 @@ import org.apereo.cas.client.proxy.ProxyRetriever;
* {@link org.apereo.cas.client.authentication.AttributePrincipalImpl} which is used with * {@link org.apereo.cas.client.authentication.AttributePrincipalImpl} which is used with
* {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. Type * {@link org.springframework.security.cas.authentication.CasAuthenticationToken}. Type
* information will be stored in property named @class. * information will be stored in property named @class.
*
* <p> * <p>
* <pre> * <pre>
* ObjectMapper mapper = new ObjectMapper(); * ObjectMapper mapper = new ObjectMapper();
@ -41,12 +40,7 @@ import org.apereo.cas.client.proxy.ProxyRetriever;
* @since 4.2 * @since 4.2
* @see CasJackson2Module * @see CasJackson2Module
* @see org.springframework.security.jackson2.SecurityJackson2Modules * @see org.springframework.security.jackson2.SecurityJackson2Modules
* @deprecated as of 7.0 in favor of
* {@code org.springframework.security.cas.jackson.AttributePrincipalImplMixin} based on
* Jackson 3
*/ */
@SuppressWarnings("removal")
@Deprecated(forRemoval = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE) isGetterVisibility = JsonAutoDetect.Visibility.NONE)

View File

@ -40,6 +40,7 @@ import org.springframework.security.core.userdetails.UserDetails;
* </ol> * </ol>
* *
* <p> * <p>
*
* <pre> * <pre>
* ObjectMapper mapper = new ObjectMapper(); * ObjectMapper mapper = new ObjectMapper();
* mapper.registerModule(new CasJackson2Module()); * mapper.registerModule(new CasJackson2Module());
@ -49,12 +50,7 @@ import org.springframework.security.core.userdetails.UserDetails;
* @since 4.2 * @since 4.2
* @see CasJackson2Module * @see CasJackson2Module
* @see org.springframework.security.jackson2.SecurityJackson2Modules * @see org.springframework.security.jackson2.SecurityJackson2Modules
* @deprecated as of 7.0 in favor of
* {@code org.springframework.security.cas.jackson.CasAuthenticationTokenMixin} based on
* Jackson 3
*/ */
@SuppressWarnings("removal")
@Deprecated(forRemoval = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY) getterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY)

View File

@ -37,14 +37,11 @@ import org.springframework.security.jackson2.SecurityJackson2Modules;
* </pre> <b>Note: use {@link SecurityJackson2Modules#getModules(ClassLoader)} to get list * </pre> <b>Note: use {@link SecurityJackson2Modules#getModules(ClassLoader)} to get list
* of all security modules on the classpath.</b> * of all security modules on the classpath.</b>
* *
* @author Jitendra Singh * @author Jitendra Singh.
* @since 4.2 * @since 4.2
* @see org.springframework.security.jackson2.SecurityJackson2Modules * @see org.springframework.security.jackson2.SecurityJackson2Modules
* @deprecated as of 7.0 in favor of
* {@link org.springframework.security.cas.jackson.CasJacksonModule} based on Jackson 3
*/ */
@Deprecated(forRemoval = true) @SuppressWarnings("serial")
@SuppressWarnings({ "serial", "removal" })
public class CasJackson2Module extends SimpleModule { public class CasJackson2Module extends SimpleModule {
public CasJackson2Module() { public CasJackson2Module() {

View File

@ -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.
*/
/**
* Jackson 2 support for CAS.
*/
@NullMarked
package org.springframework.security.cas.jackson2;
import org.jspecify.annotations.NullMarked;

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