Compare commits

..

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

950 changed files with 3136 additions and 18973 deletions

123
.github/dependabot.yml vendored
View File

@ -1,10 +1,12 @@
version: 2 version: 2
registries: registries:
spring-milestones:
type: maven-repository
url: https://repo.spring.io/milestone
shibboleth: shibboleth:
type: maven-repository type: maven-repository
url: https://build.shibboleth.net/maven/releases url: https://build.shibboleth.net/maven/releases
updates: updates:
# 6.5.x
- package-ecosystem: gradle - package-ecosystem: gradle
target-branch: 6.5.x target-branch: 6.5.x
directory: / directory: /
@ -15,6 +17,7 @@ updates:
labels: labels:
- 'type: dependency-upgrade' - 'type: dependency-upgrade'
registries: registries:
- spring-milestones
- shibboleth - shibboleth
ignore: ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt - dependency-name: com.nimbusds:nimbus-jose-jwt
@ -31,28 +34,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.4.x
directory: / directory: /
schedule: schedule:
interval: daily interval: daily
@ -61,10 +44,10 @@ updates:
labels: labels:
- 'type: dependency-upgrade' - 'type: dependency-upgrade'
registries: registries:
- spring-milestones
- shibboleth - shibboleth
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 +57,11 @@ 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,6 +72,7 @@ updates:
labels: labels:
- 'type: dependency-upgrade' - 'type: dependency-upgrade'
registries: registries:
- spring-milestones
- shibboleth - shibboleth
ignore: ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt - dependency-name: com.nimbusds:nimbus-jose-jwt
@ -131,6 +92,17 @@ updates:
- dependency-name: '*' - dependency-name: '*'
update-types: update-types:
- version-update:semver-major - version-update:semver-major
- version-update:semver-minor
- package-ecosystem: npm
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
- package-ecosystem: npm - package-ecosystem: npm
target-branch: main target-branch: main
directory: /docs directory: /docs
@ -138,63 +110,4 @@ updates:
interval: weekly interval: weekly
labels: labels:
- 'type: task' - 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
- package-ecosystem: github-actions
target-branch: main
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
# docs-build
- package-ecosystem: gradle
target-branch: docs-build
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
registries:
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:*
- dependency-name: org.apache.directory.shared:*
- dependency-name: org.junit:junit-bom
update-types:
- version-update:semver-major
- dependency-name: org.mockito:mockito-bom
update-types:
- version-update:semver-major
- dependency-name: com.gradle.enterprise
update-types:
- version-update:semver-major
- version-update:semver-minor
- dependency-name: '*'
update-types:
- version-update:semver-major
- package-ecosystem: npm
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
- package-ecosystem: github-actions
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build' - '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

@ -14,12 +14,14 @@ permissions:
jobs: jobs:
snapshot-test: snapshot-test:
name: Test Against Snapshots name: Test Against Snapshots
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14 uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1
strategy: strategy:
matrix: matrix:
include: include:
- java-version: 25 - java-version: 21-ea
toolchain: 25 toolchain: 21
- java-version: 17
toolchain: 17
with: with:
java-version: ${{ matrix.java-version }} 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 test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
@ -31,6 +33,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Send Notification - name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14 uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
with: with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}

View File

@ -21,7 +21,7 @@ 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 }}
@ -34,7 +34,6 @@ jobs:
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 default-publish-milestones-central: true
java-version: 25
secrets: inherit secrets: inherit
deploy-schema: deploy-schema:
name: Deploy Schema name: Deploy Schema
@ -42,7 +41,6 @@ jobs:
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
@ -55,7 +53,6 @@ jobs:
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

@ -16,7 +16,7 @@ permissions:
jobs: jobs:
perform-release: perform-release:
name: Perform Release name: Perform Release
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14 uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1
with: with:
should-perform-release: true should-perform-release: true
project-version: ${{ inputs.version }} project-version: ${{ inputs.version }}

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.5.x, 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: [ '6.4.x', '6.5.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

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]]
@ -94,7 +94,7 @@ Don't worry if you don't get them all correct the first time, we will help you.
1. [[sign-cla]] All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. 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,8 +1,3 @@
plugins {
id 'compile-warnings-error'
id 'javadoc-warnings-error'
}
apply plugin: 'io.spring.convention.spring-module' apply plugin: 'io.spring.convention.spring-module'
dependencies { dependencies {

View File

@ -31,7 +31,6 @@ import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource; import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource;
import org.springframework.util.StringUtils;
/** /**
* Sources method security metadata from major JSR 250 security annotations. * Sources method security metadata from major JSR 250 security annotations.
@ -109,7 +108,7 @@ public class Jsr250MethodSecurityMetadataSource extends AbstractFallbackMethodSe
if (role == null) { if (role == null) {
return role; return role;
} }
if (!StringUtils.hasLength(this.defaultRolePrefix)) { if (this.defaultRolePrefix == null || this.defaultRolePrefix.length() == 0) {
return role; return role;
} }
if (role.startsWith(this.defaultRolePrefix)) { if (role.startsWith(this.defaultRolePrefix)) {

View File

@ -53,9 +53,7 @@ import org.springframework.util.CollectionUtils;
* *
* @author Ben Alex * @author Ben Alex
* @author Luke Taylor * @author Luke Taylor
* @deprecated Use * @deprecated Use {@link EnableMethodSecurity} or publish interceptors directly
* <code>org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity</code>
* or publish interceptors directly
*/ */
@NullUnmarked @NullUnmarked
@Deprecated @Deprecated

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

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

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

@ -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;
@ -226,8 +224,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 +264,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 +323,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 +399,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 +506,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 +579,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 +670,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

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

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 {

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 {

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

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

@ -5,7 +5,7 @@ def toolchainVersion() {
if (project.hasProperty('testToolchain')) { if (project.hasProperty('testToolchain')) {
return project.property('testToolchain').toString().toInteger() return project.property('testToolchain').toString().toInteger()
} }
return 25 return 17
} }
java { java {

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

@ -1,7 +1,5 @@
plugins { plugins {
id 'security-nullability' 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'

View File

@ -24,6 +24,7 @@ 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.NullUnmarked;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@ -165,6 +166,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
* @param authentication * @param authentication
* @return * @return
*/ */
@NullUnmarked
private @Nullable String getServiceUrl(Authentication authentication) { private @Nullable String getServiceUrl(Authentication authentication) {
String serviceUrl; String serviceUrl;
if (authentication.getDetails() instanceof ServiceAuthenticationDetails) { if (authentication.getDetails() instanceof ServiceAuthenticationDetails) {

View File

@ -17,7 +17,4 @@
/** /**
* Jackson 3+ serialization support for CAS. * Jackson 3+ serialization support for CAS.
*/ */
@NullMarked
package org.springframework.security.cas.jackson; package org.springframework.security.cas.jackson;
import org.jspecify.annotations.NullMarked;

View File

@ -91,8 +91,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
*/ */
protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) { protected String createServiceUrl(HttpServletRequest request, HttpServletResponse response) {
return WebUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null, return WebUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null,
this.serviceProperties.getServiceParameter(), this.serviceProperties.getArtifactParameter(), this.serviceProperties.getArtifactParameter(), this.encodeServiceUrlWithSessionId);
this.encodeServiceUrlWithSessionId);
} }
/** /**

View File

@ -34,7 +34,6 @@ import org.springframework.util.Assert;
* and using the current URL minus the artifact and the corresponding value. * and using the current URL minus the artifact and the corresponding value.
* *
* @author Rob Winch * @author Rob Winch
* @author Ngoc Nhan
*/ */
final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
implements ServiceAuthenticationDetails { implements ServiceAuthenticationDetails {
@ -75,9 +74,10 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails that)) { if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) {
return false; return false;
} }
ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj;
return this.serviceUrl.equals(that.getServiceUrl()); return this.serviceUrl.equals(that.getServiceUrl());
} }
@ -101,11 +101,7 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
/** /**
* If present, removes the artifactParameterName and the corresponding value from the * If present, removes the artifactParameterName and the corresponding value from the
* query String. * query String.
* @param request the current {@link HttpServletRequest} to obtain the * @param request
* {@link #getServiceUrl()} from.
* @param artifactPattern the {@link Pattern} that will be used to clean up the query
* string from containing the artifact name and value. This can be created using
* {@link #createArtifactPattern(String)}.
* @return the query String minus the artifactParameterName and the corresponding * @return the query String minus the artifactParameterName and the corresponding
* value. * value.
*/ */
@ -115,7 +111,7 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
return null; return null;
} }
String result = artifactPattern.matcher(query).replaceFirst(""); String result = artifactPattern.matcher(query).replaceFirst("");
if (result.isEmpty()) { if (result.length() == 0) {
return null; return null;
} }
// strip off the trailing & only if the artifact was the first query param // strip off the trailing & only if the artifact was the first query param
@ -126,9 +122,8 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
* Creates a {@link Pattern} that can be passed into the constructor. This allows the * Creates a {@link Pattern} that can be passed into the constructor. This allows the
* {@link Pattern} to be reused for every instance of * {@link Pattern} to be reused for every instance of
* {@link DefaultServiceAuthenticationDetails}. * {@link DefaultServiceAuthenticationDetails}.
* @param artifactParameterName the artifactParameterName that is removed from the * @param artifactParameterName
* current URL. The result becomes the service url. Cannot be null or an empty String. * @return
* @return a {@link Pattern}
*/ */
static Pattern createArtifactPattern(String artifactParameterName) { static Pattern createArtifactPattern(String artifactParameterName) {
Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length"); Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length");

View File

@ -4,9 +4,6 @@ import trang.RncToXsd
apply plugin: 'io.spring.convention.spring-module' apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'trang' apply plugin: 'trang'
apply plugin: 'security-kotlin' apply plugin: 'security-kotlin'
apply plugin: 'test-compile-target-jdk25'
apply plugin: 'compile-warnings-error'
apply plugin: 'javadoc-warnings-error'
configurations { configurations {
opensaml5 { opensaml5 {

View File

@ -1,126 +0,0 @@
package org.springframework.security.config.ldap;
import javax.naming.Name;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.support.BaseLdapPathAware;
import org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.server.UnboundIdContainer;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringTestContextExtension.class)
public class Ldap247ITests {
public final SpringTestContext spring = new SpringTestContext(this);
@Autowired
private LdapGroupDao ldapGroupDao;
@Test
public void verifyThatBasePathIsProperlyPopulated() {
this.spring.register(FromContextSourceConfig.class).autowire();
assertThat(this.ldapGroupDao).isNotNull();
assertThat(this.ldapGroupDao.getBasePath()).isNotNull();
}
@Configuration
@EnableMethodSecurity
@Import(BaseLdapServerConfig.class)
static class FromContextSourceConfig {
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
return factory.createAuthenticationManager();
}
@Bean
static MethodSecurityExpressionHandler securityExpressionHandler(LdapGroupDao ldap) {
return new MethodSecurityExpressionHandler(ldap);
}
@Bean
static LdapGroupDao ldapGroupDao() {
return new LdapGroupDao();
}
@Bean
static BaseLdapPathBeanPostProcessor baseLdapPathBeanPostProcessor() {
return new BaseLdapPathBeanPostProcessor();
}
}
@Configuration
@EnableWebSecurity
static class BaseLdapServerConfig implements DisposableBean {
private UnboundIdContainer container;
@Bean
UnboundIdContainer ldapServer() {
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
this.container.setPort(0);
return this.container;
}
@Bean
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
int port = container.getPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
}
@Override
public void destroy() {
this.container.stop();
}
}
static class MethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final LdapGroupDao groupDao;
MethodSecurityExpressionHandler(LdapGroupDao groupDao) {
this.groupDao = groupDao;
}
}
static class LdapGroupDao implements BaseLdapPathAware {
private Name basePath;
LdapGroupDao() {
super();
}
@Override
public void setBaseLdapPath(DistinguishedName baseLdapPath) {
this.basePath = baseLdapPath;
}
public Name getBasePath() {
return this.basePath;
}
}
}

View File

@ -20,7 +20,6 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.jspecify.annotations.NullMarked;
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;
@ -99,14 +98,12 @@ public class LdapBindAuthenticationManagerFactoryITests {
public void authenticationManagerFactoryWhenCustomUserDetailsContextMapperThenUsed() throws Exception { public void authenticationManagerFactoryWhenCustomUserDetailsContextMapperThenUsed() throws Exception {
CustomUserDetailsContextMapperConfig.CONTEXT_MAPPER = new UserDetailsContextMapper() { CustomUserDetailsContextMapperConfig.CONTEXT_MAPPER = new UserDetailsContextMapper() {
@Override @Override
@NullMarked
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) { Collection<? extends GrantedAuthority> authorities) {
return User.withUsername("other").password("password").roles("USER").build(); return User.withUsername("other").password("password").roles("USER").build();
} }
@Override @Override
@NullMarked
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) { public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
} }
}; };

View File

@ -94,7 +94,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
public BeanDefinition parse(Element element, ParserContext pc) { public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) { if (!namespaceMatchesVersion(element)) {
pc.getReaderContext() pc.getReaderContext()
.fatal("You cannot use any XSD older than spring-security-7.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd", .fatal("You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd",
element); element);
} }
String name = pc.getDelegate().getLocalName(element); String name = pc.getDelegate().getLocalName(element);
@ -219,7 +219,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private boolean matchesVersionInternal(Element element) { private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"); String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-7\\.1.*.xsd.*") return schemaLocation.matches("(?m).*spring-security-7\\.0.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*") || schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*"); || !schemaLocation.matches("(?m).*spring-security.*");
} }

View File

@ -36,7 +36,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.log.LogMessage; import org.springframework.core.log.LogMessage;
import org.springframework.lang.Contract;
import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
@ -303,7 +302,6 @@ public class AuthenticationConfiguration {
} }
@Override @Override
@Contract("!null -> !null; null -> null")
public String encode(CharSequence rawPassword) { public String encode(CharSequence rawPassword) {
return getPasswordEncoder().encode(rawPassword); return getPasswordEncoder().encode(rawPassword);
} }

View File

@ -1881,7 +1881,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* *
* <p> * <p>
* Invoking {@link #securityMatchers(Customizer)} will not override previous * Invoking {@link #securityMatchers(Customizer)} will not override previous
* invocations of {@link #securityMatchers(Customizer)} * invocations of {@link #securityMatchers()}}, {@link #securityMatchers(Customizer)}
* {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)} * {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)}
* </p> * </p>
* *
@ -2004,7 +2004,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* <p> * <p>
* Invoking {@link #securityMatcher(RequestMatcher)} will override previous * Invoking {@link #securityMatcher(RequestMatcher)} will override previous
* invocations of {@link #securityMatcher(RequestMatcher)}, * invocations of {@link #securityMatcher(RequestMatcher)},
* {@link #securityMatcher(String...)} and {@link #securityMatchers(Customizer)} * {@link #securityMatcher(String...)}, {@link #securityMatchers(Customizer)} and
* {@link #securityMatchers()}
* </p> * </p>
* @param requestMatcher the {@link RequestMatcher} to use, for example, * @param requestMatcher the {@link RequestMatcher} to use, for example,
* {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")} * {@code PathPatternRequestMatcher.pathPattern(HttpMethod.GET, "/admin/**")}
@ -2023,8 +2024,9 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* *
* <p> * <p>
* Invoking {@link #securityMatcher(String...)} will override previous invocations of * Invoking {@link #securityMatcher(String...)} will override previous invocations of
* {@link #securityMatcher(String...)}, {@link #securityMatcher(RequestMatcher)} and * {@link #securityMatcher(String...)} (String)}},
* {@link #securityMatchers(Customizer)}. * {@link #securityMatcher(RequestMatcher)} ()}, {@link #securityMatchers(Customizer)}
* (String)} and {@link #securityMatchers()} (String)}.
* </p> * </p>
* @param patterns the pattern to match on (i.e. "/admin/**") * @param patterns the pattern to match on (i.e. "/admin/**")
* @return the {@link HttpSecurity} for further customizations * @return the {@link HttpSecurity} for further customizations

View File

@ -226,7 +226,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
* *
* <p> * <p>
* Typically this method is invoked automatically within the framework from * Typically this method is invoked automatically within the framework from
* {@link WebSecurityConfiguration#springSecurityFilterChain(ObjectProvider)} * {@link WebSecurityConfiguration#springSecurityFilterChain()}
* </p> * </p>
* @param securityFilterChainBuilder the builder to use to create the * @param securityFilterChainBuilder the builder to use to create the
* {@link SecurityFilterChain} instances * {@link SecurityFilterChain} instances

View File

@ -30,7 +30,6 @@ import org.springframework.context.annotation.Scope;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.lang.Contract;
import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
@ -294,7 +293,6 @@ class HttpSecurityConfiguration {
} }
@Override @Override
@Contract("!null -> !null; null -> null")
public String encode(CharSequence rawPassword) { public String encode(CharSequence rawPassword) {
return getPasswordEncoder().encode(rawPassword); return getPasswordEncoder().encode(rawPassword);
} }

View File

@ -39,7 +39,6 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
* other than applying this {@link SecurityConfigurer}. * other than applying this {@link SecurityConfigurer}.
* *
* @author Rob Winch * @author Rob Winch
* @author DingHao
* @since 3.2 * @since 3.2
*/ */
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
@ -159,7 +158,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
} }
this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
this.authenticationFilter.afterPropertiesSet(); this.authenticationFilter.afterPropertiesSet();
http.addFilter(postProcess(this.authenticationFilter)); http.addFilter(this.authenticationFilter);
} }
private String getKey() { private String getKey() {

View File

@ -47,8 +47,8 @@ import org.springframework.util.Assert;
* The following configuration options are available: * The following configuration options are available:
* *
* <ul> * <ul>
* <li>{@link #authorizationCodeGrant(Customizer)} - support for the OAuth 2.0 * <li>{@link #authorizationCodeGrant()} - support for the OAuth 2.0 Authorization Code
* Authorization Code Grant</li> * Grant</li>
* </ul> * </ul>
* *
* <p> * <p>
@ -59,8 +59,7 @@ import org.springframework.util.Assert;
* *
* <h2>Security Filters</h2> * <h2>Security Filters</h2>
* *
* The following {@code Filter}'s are populated for * The following {@code Filter}'s are populated for {@link #authorizationCodeGrant()}:
* {@link #authorizationCodeGrant(Customizer)}:
* *
* <ul> * <ul>
* <li>{@link OAuth2AuthorizationRequestRedirectFilter}</li> * <li>{@link OAuth2AuthorizationRequestRedirectFilter}</li>

View File

@ -40,11 +40,11 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
import org.springframework.security.oauth2.server.authorization.web.OAuth2DeviceVerificationEndpointFilter; import org.springframework.security.oauth2.server.authorization.web.OAuth2DeviceVerificationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceAuthorizationConsentAuthenticationConverter; import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceAuthorizationConsentAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceVerificationAuthenticationConverter; import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceVerificationAuthenticationConverter;
import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.DelegatingAuthenticationConverter; import org.springframework.security.web.authentication.DelegatingAuthenticationConverter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
@ -279,7 +279,8 @@ public final class OAuth2DeviceVerificationEndpointConfigurer extends AbstractOA
if (StringUtils.hasText(this.consentPage)) { if (StringUtils.hasText(this.consentPage)) {
deviceVerificationEndpointFilter.setConsentPage(this.consentPage); deviceVerificationEndpointFilter.setConsentPage(this.consentPage);
} }
builder.addFilterAfter(postProcess(deviceVerificationEndpointFilter), AuthorizationFilter.class); builder.addFilterBefore(postProcess(deviceVerificationEndpointFilter),
AbstractPreAuthenticatedProcessingFilter.class);
} }
@Override @Override

View File

@ -521,10 +521,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
public OpaqueTokenConfigurer introspectionUri(String introspectionUri) { public OpaqueTokenConfigurer introspectionUri(String introspectionUri) {
Assert.notNull(introspectionUri, "introspectionUri cannot be null"); Assert.notNull(introspectionUri, "introspectionUri cannot be null");
this.introspectionUri = introspectionUri; this.introspectionUri = introspectionUri;
this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri) this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
.clientId(this.clientId) this.clientSecret);
.clientSecret(this.clientSecret)
.build();
return this; return this;
} }
@ -533,10 +531,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
Assert.notNull(clientSecret, "clientSecret cannot be null"); Assert.notNull(clientSecret, "clientSecret cannot be null");
this.clientId = clientId; this.clientId = clientId;
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri) this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
.clientId(this.clientId) this.clientSecret);
.clientSecret(this.clientSecret)
.build();
return this; return this;
} }

View File

@ -21,7 +21,6 @@ import java.util.function.Function;
import org.opensaml.core.Version; import org.opensaml.core.Version;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
@ -43,8 +42,7 @@ import org.springframework.util.Assert;
* *
* <p> * <p>
* Defaults are provided for all configuration options with the only required * Defaults are provided for all configuration options with the only required
* configuration being a * configuration being a {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository}.
* {@link Saml2LoginConfigurer#relyingPartyRegistrationRepository(HttpSecurityBuilder)}.
* Alternatively, a {@link RelyingPartyRegistrationRepository} {@code @Bean} may be * Alternatively, a {@link RelyingPartyRegistrationRepository} {@code @Bean} may be
* registered instead. * registered instead.
* *
@ -69,7 +67,7 @@ import org.springframework.util.Assert;
* </ul> * </ul>
* *
* @since 6.1 * @since 6.1
* @see HttpSecurity#saml2Metadata(Customizer) * @see HttpSecurity#saml2Metadata()
* @see Saml2MetadataFilter * @see Saml2MetadataFilter
* @see RelyingPartyRegistrationRepository * @see RelyingPartyRegistrationRepository
*/ */

View File

@ -255,9 +255,7 @@ class ServerHttpSecurityConfiguration {
if (this.passwordEncoder != null) { if (this.passwordEncoder != null) {
manager.setPasswordEncoder(this.passwordEncoder); manager.setPasswordEncoder(this.passwordEncoder);
} }
if (this.userDetailsPasswordService != null) { manager.setUserDetailsPasswordService(this.userDetailsPasswordService);
manager.setUserDetailsPasswordService(this.userDetailsPasswordService);
}
manager.setCompromisedPasswordChecker(this.compromisedPasswordChecker); manager.setCompromisedPasswordChecker(this.compromisedPasswordChecker);
return this.postProcessor.postProcess(manager); return this.postProcessor.postProcess(manager);
} }

View File

@ -124,10 +124,6 @@ class AuthorizationFilterParser implements BeanDefinitionParser {
List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL); List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
for (Element interceptMessage : interceptMessages) { for (Element interceptMessage : interceptMessages) {
String accessExpression = interceptMessage.getAttribute(ATT_ACCESS); String accessExpression = interceptMessage.getAttribute(ATT_ACCESS);
if (!StringUtils.hasText(accessExpression)) {
parserContext.getReaderContext().error("access attribute cannot be empty or null", interceptMessage);
continue;
}
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
.rootBeanDefinition(WebExpressionAuthorizationManager.class); .rootBeanDefinition(WebExpressionAuthorizationManager.class);
authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef); authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef);

View File

@ -142,11 +142,10 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
ManagedMap<BeanMetadataElement, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<>(); ManagedMap<BeanMetadataElement, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<>();
for (Element urlElt : urlElts) { for (Element urlElt : urlElts) {
String access = urlElt.getAttribute(ATT_ACCESS); String access = urlElt.getAttribute(ATT_ACCESS);
String path = urlElt.getAttribute(ATT_PATTERN);
if (!StringUtils.hasText(access)) { if (!StringUtils.hasText(access)) {
parserContext.getReaderContext().error("access attribute cannot be empty or null", urlElt);
continue; continue;
} }
String path = urlElt.getAttribute(ATT_PATTERN);
String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF); String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF);
boolean hasMatcherRef = StringUtils.hasText(matcherRef); boolean hasMatcherRef = StringUtils.hasText(matcherRef);
if (!hasMatcherRef && !StringUtils.hasText(path)) { if (!hasMatcherRef && !StringUtils.hasText(path)) {

View File

@ -2162,7 +2162,7 @@ public class ServerHttpSecurity {
* *
* @author Evgeniy Cheban * @author Evgeniy Cheban
* @since 5.6 * @since 5.6
* @see #passwordManagement(Customizer) * @see #passwordManagement()
*/ */
public final class PasswordManagementSpec { public final class PasswordManagementSpec {
@ -2663,7 +2663,7 @@ public class ServerHttpSecurity {
/** /**
* Configures cache control headers * Configures cache control headers
* *
* @see HeaderSpec#cache(Customizer) * @see #cache()
*/ */
public final class CacheSpec { public final class CacheSpec {
@ -2684,7 +2684,7 @@ public class ServerHttpSecurity {
/** /**
* The content type headers * The content type headers
* *
* @see HeaderSpec#contentTypeOptions(Customizer) * @see #contentTypeOptions()
*/ */
public final class ContentTypeOptionsSpec { public final class ContentTypeOptionsSpec {
@ -2705,7 +2705,7 @@ public class ServerHttpSecurity {
/** /**
* Configures frame options response header * Configures frame options response header
* *
* @see HeaderSpec#frameOptions(Customizer) * @see #frameOptions()
*/ */
public final class FrameOptionsSpec { public final class FrameOptionsSpec {
@ -2737,7 +2737,7 @@ public class ServerHttpSecurity {
/** /**
* Configures Strict Transport Security response header * Configures Strict Transport Security response header
* *
* @see HeaderSpec#hsts(Customizer) * @see #hsts()
*/ */
public final class HstsSpec { public final class HstsSpec {
@ -2796,7 +2796,7 @@ public class ServerHttpSecurity {
/** /**
* Configures x-xss-protection response header * Configures x-xss-protection response header
* *
* @see HeaderSpec#xssProtection(Customizer) * @see #xssProtection()
*/ */
public final class XssProtectionSpec { public final class XssProtectionSpec {
@ -2830,7 +2830,7 @@ public class ServerHttpSecurity {
* Configures {@code Content-Security-Policy} response header. * Configures {@code Content-Security-Policy} response header.
* *
* @since 5.1 * @since 5.1
* @see HeaderSpec#contentSecurityPolicy(Customizer) * @see #contentSecurityPolicy(String)
*/ */
public final class ContentSecurityPolicySpec { public final class ContentSecurityPolicySpec {
@ -2884,7 +2884,8 @@ public class ServerHttpSecurity {
* Allows method chaining to continue configuring the * Allows method chaining to continue configuring the
* {@link ServerHttpSecurity}. * {@link ServerHttpSecurity}.
* @return the {@link HeaderSpec} to continue configuring * @return the {@link HeaderSpec} to continue configuring
* @deprecated For removal in 7.0. Use {@link #featurePolicy(String)} instead * @deprecated For removal in 7.0. Use {@link #featurePolicy(Customizer)}
* instead
*/ */
@Deprecated(since = "6.1", forRemoval = true) @Deprecated(since = "6.1", forRemoval = true)
public HeaderSpec and() { public HeaderSpec and() {
@ -2897,7 +2898,7 @@ public class ServerHttpSecurity {
* Configures {@code Permissions-Policy} response header. * Configures {@code Permissions-Policy} response header.
* *
* @since 5.5 * @since 5.5
* @see HeaderSpec#permissionsPolicy(Customizer) * @see #permissionsPolicy()
*/ */
public final class PermissionsPolicySpec { public final class PermissionsPolicySpec {
@ -2920,7 +2921,8 @@ public class ServerHttpSecurity {
* Configures {@code Referrer-Policy} response header. * Configures {@code Referrer-Policy} response header.
* *
* @since 5.1 * @since 5.1
* @see HeaderSpec#referrerPolicy(Customizer) * @see #referrerPolicy()
* @see #referrerPolicy(ReferrerPolicy)
*/ */
public final class ReferrerPolicySpec { public final class ReferrerPolicySpec {

View File

@ -23,7 +23,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@ -42,18 +44,25 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext; import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.simp.SimpMessageType; import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.vote.ConsensusBased; import org.springframework.security.access.vote.ConsensusBased;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.config.Elements; import org.springframework.security.config.Elements;
import org.springframework.security.config.http.MessageMatcherFactoryBean; import org.springframework.security.config.http.MessageMatcherFactoryBean;
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean; import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory; import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
import org.springframework.security.messaging.access.expression.MessageExpressionAuthorizationManager; import org.springframework.security.messaging.access.expression.MessageAuthorizationContextSecurityExpressionHandler;
import org.springframework.security.messaging.access.expression.MessageExpressionVoter; import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor; import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor;
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
@ -66,6 +75,7 @@ import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatche
import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor; import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor; import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher; import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils; import org.springframework.util.xml.DomUtils;
@ -209,15 +219,9 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
String messageType = interceptMessage.getAttribute(TYPE_ATTR); String messageType = interceptMessage.getAttribute(TYPE_ATTR);
BeanDefinition matcher = createMatcher(matcherPattern, messageType, parserContext, interceptMessage); BeanDefinition matcher = createMatcher(matcherPattern, messageType, parserContext, interceptMessage);
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
.rootBeanDefinition(MessageExpressionAuthorizationManager.class); .rootBeanDefinition(ExpressionBasedAuthorizationManager.class);
if (StringUtils.hasText(expressionHandlerRef)) { if (StringUtils.hasText(expressionHandlerRef)) {
BeanDefinitionBuilder authorizationManagerBuilder = BeanDefinitionBuilder authorizationManager.addConstructorArgReference(expressionHandlerRef);
.rootBeanDefinition(MessageExpressionAuthorizationManager.class);
authorizationManagerBuilder.setFactoryMethod("withSecurityExpressionHandler");
authorizationManagerBuilder.addConstructorArgReference(expressionHandlerRef);
String authorizationManagerBuilderRef = context
.registerWithGeneratedName(authorizationManagerBuilder.getBeanDefinition());
authorizationManager.setFactoryMethodOnBean("expression", authorizationManagerBuilderRef);
} }
authorizationManager.addConstructorArgValue(accessExpression); authorizationManager.addConstructorArgValue(accessExpression);
matcherToExpression.put(matcher, authorizationManager.getBeanDefinition()); matcherToExpression.put(matcher, authorizationManager.getBeanDefinition());
@ -435,6 +439,35 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
} }
private static final class ExpressionBasedAuthorizationManager
implements AuthorizationManager<MessageAuthorizationContext<?>> {
private final SecurityExpressionHandler<MessageAuthorizationContext<?>> expressionHandler;
private final Expression expression;
private ExpressionBasedAuthorizationManager(String expression) {
this(new MessageAuthorizationContextSecurityExpressionHandler(), expression);
}
private ExpressionBasedAuthorizationManager(
SecurityExpressionHandler<MessageAuthorizationContext<?>> expressionHandler, String expression) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
Assert.notNull(expression, "expression cannot be null");
this.expressionHandler = expressionHandler;
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expression);
}
@Override
public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
MessageAuthorizationContext<?> object) {
EvaluationContext context = this.expressionHandler.createEvaluationContext(authentication, object);
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, context);
return new AuthorizationDecision(granted);
}
}
private static class MessageMatcherDelegatingAuthorizationManagerFactory { private static class MessageMatcherDelegatingAuthorizationManagerFactory {
private static AuthorizationManager<Message<?>> createMessageMatcherDelegatingAuthorizationManager( private static AuthorizationManager<Message<?>> createMessageMatcherDelegatingAuthorizationManager(

View File

@ -286,7 +286,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
if (factoryOfRequestAuthorizationContext != null) { if (factoryOfRequestAuthorizationContext != null) {
return factoryOfRequestAuthorizationContext return factoryOfRequestAuthorizationContext
} }
val factoryOfObjectType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory::class.java, Any::class.java) val factoryOfObjectType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory::class.java, Object::class.java)
val factoryOfAny = context.getBeanProvider<AuthorizationManagerFactory<Any>>(factoryOfObjectType).getIfUnique() val factoryOfAny = context.getBeanProvider<AuthorizationManagerFactory<Any>>(factoryOfObjectType).getIfUnique()
if (factoryOfAny != null) { if (factoryOfAny != null) {
return factoryOfAny return factoryOfAny
@ -303,20 +303,20 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
return defaultFactory return defaultFactory
} }
private fun resolveRolePrefix(context: ApplicationContext): String? { private fun resolveRolePrefix(context: ApplicationContext): String {
val beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults::class.java) val beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults::class.java)
if (beanNames.isNotEmpty()) { if (beanNames.isNotEmpty()) {
return context.getBean(GrantedAuthorityDefaults::class.java).rolePrefix return context.getBean(GrantedAuthorityDefaults::class.java).rolePrefix
} }
return null return "ROLE_";
} }
private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy? { private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy {
val beanNames = context.getBeanNamesForType(RoleHierarchy::class.java) val beanNames = context.getBeanNamesForType(RoleHierarchy::class.java)
if (beanNames.isNotEmpty()) { if (beanNames.isNotEmpty()) {
return context.getBean(RoleHierarchy::class.java) return context.getBean(RoleHierarchy::class.java)
} }
return null return NullRoleHierarchy()
} }
} }

View File

@ -37,11 +37,9 @@ class HeadersDsl {
private var cacheControl: ((HeadersConfigurer<HttpSecurity>.CacheControlConfig) -> Unit)? = null private var cacheControl: ((HeadersConfigurer<HttpSecurity>.CacheControlConfig) -> Unit)? = null
private var hsts: ((HeadersConfigurer<HttpSecurity>.HstsConfig) -> Unit)? = null private var hsts: ((HeadersConfigurer<HttpSecurity>.HstsConfig) -> Unit)? = null
private var frameOptions: ((HeadersConfigurer<HttpSecurity>.FrameOptionsConfig) -> Unit)? = null private var frameOptions: ((HeadersConfigurer<HttpSecurity>.FrameOptionsConfig) -> Unit)? = null
@Suppress("DEPRECATION")
private var hpkp: ((HeadersConfigurer<HttpSecurity>.HpkpConfig) -> Unit)? = null private var hpkp: ((HeadersConfigurer<HttpSecurity>.HpkpConfig) -> Unit)? = null
private var contentSecurityPolicy: ((HeadersConfigurer<HttpSecurity>.ContentSecurityPolicyConfig) -> Unit)? = null private var contentSecurityPolicy: ((HeadersConfigurer<HttpSecurity>.ContentSecurityPolicyConfig) -> Unit)? = null
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
@Suppress("DEPRECATION")
private var featurePolicyDirectives: String? = null private var featurePolicyDirectives: String? = null
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null
@ -122,7 +120,6 @@ class HeadersDsl {
* @deprecated see <a href="https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate and Public Key Pinning</a> for more context * @deprecated see <a href="https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate and Public Key Pinning</a> for more context
*/ */
@Deprecated(message = "as of 5.8 with no replacement") @Deprecated(message = "as of 5.8 with no replacement")
@Suppress("DEPRECATION")
fun httpPublicKeyPinning(hpkpConfig: HttpPublicKeyPinningDsl.() -> Unit) { fun httpPublicKeyPinning(hpkpConfig: HttpPublicKeyPinningDsl.() -> Unit) {
this.hpkp = HttpPublicKeyPinningDsl().apply(hpkpConfig).get() this.hpkp = HttpPublicKeyPinningDsl().apply(hpkpConfig).get()
} }
@ -170,7 +167,6 @@ class HeadersDsl {
* @param policyDirectives policyDirectives the security policy directive(s) * @param policyDirectives policyDirectives the security policy directive(s)
*/ */
@Deprecated("Use 'permissionsPolicy { }' instead.") @Deprecated("Use 'permissionsPolicy { }' instead.")
@Suppress("DEPRECATION")
fun featurePolicy(policyDirectives: String) { fun featurePolicy(policyDirectives: String) {
this.featurePolicyDirectives = policyDirectives this.featurePolicyDirectives = policyDirectives
} }

View File

@ -614,7 +614,6 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
* @see [RequiresChannelDsl] * @see [RequiresChannelDsl]
* @deprecated please use [redirectToHttps] instead * @deprecated please use [redirectToHttps] instead
*/ */
@Suppress("DEPRECATION")
@Deprecated(message="since 6.5 use redirectToHttps instead") @Deprecated(message="since 6.5 use redirectToHttps instead")
fun requiresChannel(requiresChannelConfiguration: RequiresChannelDsl.() -> Unit) { fun requiresChannel(requiresChannelConfiguration: RequiresChannelDsl.() -> Unit) {
val requiresChannelCustomizer = RequiresChannelDsl().apply(requiresChannelConfiguration).get() val requiresChannelCustomizer = RequiresChannelDsl().apply(requiresChannelConfiguration).get()

View File

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
@file:Suppress("DEPRECATION")
package org.springframework.security.config.annotation.web package org.springframework.security.config.annotation.web
import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.builders.HttpSecurity

View File

@ -62,7 +62,6 @@ class X509Dsl {
authenticationDetailsSource?.also { x509.authenticationDetailsSource(authenticationDetailsSource) } authenticationDetailsSource?.also { x509.authenticationDetailsSource(authenticationDetailsSource) }
userDetailsService?.also { x509.userDetailsService(userDetailsService) } userDetailsService?.also { x509.userDetailsService(userDetailsService) }
authenticationUserDetailsService?.also { x509.authenticationUserDetailsService(authenticationUserDetailsService) } authenticationUserDetailsService?.also { x509.authenticationUserDetailsService(authenticationUserDetailsService) }
@Suppress("DEPRECATION")
subjectPrincipalRegex?.also { x509.subjectPrincipalRegex(subjectPrincipalRegex) } subjectPrincipalRegex?.also { x509.subjectPrincipalRegex(subjectPrincipalRegex) }
} }
} }

View File

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
@file:Suppress("DEPRECATION")
package org.springframework.security.config.annotation.web.headers package org.springframework.security.config.annotation.web.headers
import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.builders.HttpSecurity

View File

@ -68,11 +68,12 @@ class SessionFixationDsl {
internal fun get(): (SessionManagementConfigurer<HttpSecurity>.SessionFixationConfigurer) -> Unit { internal fun get(): (SessionManagementConfigurer<HttpSecurity>.SessionFixationConfigurer) -> Unit {
return { sessionFixation -> return { sessionFixation ->
strategy?.also { strategy?.also {
when (it) { when (strategy) {
SessionFixationStrategy.NEW -> sessionFixation.newSession() SessionFixationStrategy.NEW -> sessionFixation.newSession()
SessionFixationStrategy.MIGRATE -> sessionFixation.migrateSession() SessionFixationStrategy.MIGRATE -> sessionFixation.migrateSession()
SessionFixationStrategy.CHANGE_ID -> sessionFixation.changeSessionId() SessionFixationStrategy.CHANGE_ID -> sessionFixation.changeSessionId()
SessionFixationStrategy.NONE -> sessionFixation.none() SessionFixationStrategy.NONE -> sessionFixation.none()
null -> null
} }
} }
} }

View File

@ -14,8 +14,6 @@
# limitations under the License. # limitations under the License.
# #
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.1.xsd
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.1.xsd
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
@ -44,8 +42,7 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.1.xsd https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd
https\://www.springframework.org/schema/security/spring-security-7.1.xsd=org/springframework/security/config/spring-security-7.1.xsd
https\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd https\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd

View File

@ -12,8 +12,8 @@ base64 =
## Whether a string should be base64 encoded ## Whether a string should be base64 encoded
attribute base64 {xsd:boolean} attribute base64 {xsd:boolean}
request-matcher = request-matcher =
## Defines the strategy use for matching incoming requests. Currently the options are 'path' (for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. ## Defines the strategy use for matching incoming requests. Currently the options are 'mvc' (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
attribute request-matcher {"path" | "regex" | "ciRegex"} attribute request-matcher {"mvc" | "ant" | "regex" | "ciRegex"}
port = port =
## Specifies an IP port number. Used to configure an embedded LDAP server, for example. ## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
attribute port { xsd:nonNegativeInteger } attribute port { xsd:nonNegativeInteger }

View File

@ -27,14 +27,15 @@
<xs:attributeGroup name="request-matcher"> <xs:attributeGroup name="request-matcher">
<xs:attribute name="request-matcher" use="required"> <xs:attribute name="request-matcher" use="required">
<xs:annotation> <xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path' <xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
case-insensitive regular expressions. and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:token"> <xs:restriction base="xs:token">
<xs:enumeration value="path"/> <xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/> <xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/> <xs:enumeration value="ciRegex"/>
</xs:restriction> </xs:restriction>
@ -1305,14 +1306,15 @@
</xs:attribute> </xs:attribute>
<xs:attribute name="request-matcher"> <xs:attribute name="request-matcher">
<xs:annotation> <xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path' <xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
case-insensitive regular expressions. and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:token"> <xs:restriction base="xs:token">
<xs:enumeration value="path"/> <xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/> <xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/> <xs:enumeration value="ciRegex"/>
</xs:restriction> </xs:restriction>
@ -2472,14 +2474,15 @@
<xs:attributeGroup name="filter-chain-map.attlist"> <xs:attributeGroup name="filter-chain-map.attlist">
<xs:attribute name="request-matcher"> <xs:attribute name="request-matcher">
<xs:annotation> <xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path' <xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
case-insensitive regular expressions. and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:token"> <xs:restriction base="xs:token">
<xs:enumeration value="path"/> <xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/> <xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/> <xs:enumeration value="ciRegex"/>
</xs:restriction> </xs:restriction>
@ -2577,14 +2580,15 @@
</xs:attribute> </xs:attribute>
<xs:attribute name="request-matcher"> <xs:attribute name="request-matcher">
<xs:annotation> <xs:annotation>
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path' <xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
case-insensitive regular expressions. and 'ciRegex' for case-insensitive regular expressions.
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:token"> <xs:restriction base="xs:token">
<xs:enumeration value="path"/> <xs:enumeration value="mvc"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/> <xs:enumeration value="regex"/>
<xs:enumeration value="ciRegex"/> <xs:enumeration value="ciRegex"/>
</xs:restriction> </xs:restriction>

View File

@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.security.Principal; import java.security.Principal;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
@ -246,15 +245,12 @@ import org.springframework.security.web.savedrequest.SimpleSavedRequest;
import org.springframework.security.web.server.firewall.ServerExchangeRejectedException; import org.springframework.security.web.server.firewall.ServerExchangeRejectedException;
import org.springframework.security.web.session.HttpSessionCreatedEvent; import org.springframework.security.web.session.HttpSessionCreatedEvent;
import org.springframework.security.web.session.HttpSessionIdChangedEvent; import org.springframework.security.web.session.HttpSessionIdChangedEvent;
import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs; import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs; import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse; import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment; import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
import org.springframework.security.web.webauthn.api.AuthenticatorTransport; import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
import org.springframework.security.web.webauthn.api.Bytes; import org.springframework.security.web.webauthn.api.Bytes;
import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput; import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput; import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput; import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
@ -262,17 +258,12 @@ import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExte
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs; import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.PublicKeyCredential; import org.springframework.security.web.webauthn.api.PublicKeyCredential;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor; import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialParameters;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions; import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType; import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses; import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
import org.springframework.security.web.webauthn.api.TestBytes; import org.springframework.security.web.webauthn.api.TestBytes;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials;
@ -280,7 +271,6 @@ import org.springframework.security.web.webauthn.api.UserVerificationRequirement
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication;
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken;
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest; import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
import org.springframework.security.web.webauthn.management.TestPublicKeyCredentialRpEntities;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
final class SerializationSamples { final class SerializationSamples {
@ -294,14 +284,6 @@ final class SerializationSamples {
Authentication authentication = TestAuthentication.authenticated(user); Authentication authentication = TestAuthentication.authenticated(user);
SecurityContext securityContext = new SecurityContextImpl(authentication); SecurityContext securityContext = new SecurityContextImpl(authentication);
instancioByClassName.put(OneTimeTokenAuthenticationToken.class, () -> {
@SuppressWarnings("removal")
InstancioOfClassApi<?> instancio = Instancio.of(OneTimeTokenAuthenticationToken.class);
instancio.supply(Select.all(OneTimeTokenAuthenticationToken.class),
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("token")));
return instancio;
});
// oauth2-core // oauth2-core
generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create()); generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create());
generatorByClassName.put(OAuth2AuthorizationRequest.class, generatorByClassName.put(OAuth2AuthorizationRequest.class,
@ -615,7 +597,8 @@ final class SerializationSamples {
token.setDetails(details); token.setDetails(details);
return token; return token;
}); });
generatorByClassName.put(OneTimeTokenAuthenticationToken.class,
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token")));
generatorByClassName.put(OneTimeTokenAuthentication.class, generatorByClassName.put(OneTimeTokenAuthentication.class,
(r) -> applyDetails(new OneTimeTokenAuthentication("username", authentication.getAuthorities()))); (r) -> applyDetails(new OneTimeTokenAuthentication("username", authentication.getAuthorities())));
generatorByClassName.put(AccessDeniedException.class, generatorByClassName.put(AccessDeniedException.class,
@ -896,36 +879,6 @@ final class SerializationSamples {
generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class, generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class,
(r) -> new CredentialPropertiesOutput(true).getOutput()); (r) -> new CredentialPropertiesOutput(true).getOutput());
AttestationConveyancePreference attestationConveyancePreference = AttestationConveyancePreference.DIRECT;
ResidentKeyRequirement residentKeyRequirement = ResidentKeyRequirement.REQUIRED;
AuthenticatorSelectionCriteria authenticatorSelectionCriteria = AuthenticatorSelectionCriteria.builder()
.authenticatorAttachment(AuthenticatorAttachment.PLATFORM)
.residentKey(residentKeyRequirement)
.userVerification(UserVerificationRequirement.REQUIRED)
.build();
PublicKeyCredentialParameters publicKeyCredentialParameters = PublicKeyCredentialParameters.RS256;
PublicKeyCredentialRpEntity publicKeyCredentialRpEntity = TestPublicKeyCredentialRpEntities.createRpEntity()
.build();
generatorByClassName.put(AttestationConveyancePreference.class, (r) -> attestationConveyancePreference);
generatorByClassName.put(ResidentKeyRequirement.class, (r) -> residentKeyRequirement);
generatorByClassName.put(AuthenticatorSelectionCriteria.class, (r) -> authenticatorSelectionCriteria);
generatorByClassName.put(COSEAlgorithmIdentifier.class, ((r) -> COSEAlgorithmIdentifier.RS256));
generatorByClassName.put(PublicKeyCredentialParameters.class, (r) -> publicKeyCredentialParameters);
generatorByClassName.put(PublicKeyCredentialRpEntity.class, (r) -> publicKeyCredentialRpEntity);
generatorByClassName.put(PublicKeyCredentialCreationOptions.class,
(o) -> TestPublicKeyCredentialCreationOptions.createPublicKeyCredentialCreationOptions()
.extensions(inputs)
.attestation(attestationConveyancePreference)
.authenticatorSelection(authenticatorSelectionCriteria)
.challenge(TestBytes.get())
.excludeCredentials(List.of(descriptor))
.rp(publicKeyCredentialRpEntity)
.pubKeyCredParams(publicKeyCredentialParameters)
.timeout(Duration.ofMinutes(5))
.user(TestPublicKeyCredentialUserEntities.userEntity().id(TestBytes.get()).build())
.build());
// One-Time Token // One-Time Token
DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user", DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user",
Instant.now().plusSeconds(300)); Instant.now().plusSeconds(300));

View File

@ -114,7 +114,7 @@ public class SecurityNamespaceHandlerTests {
"<user-service id='us'><user name='bob' password='bobspassword' authorities='ROLE_A' /></user-service>", "<user-service id='us'><user name='bob' password='bobspassword' authorities='ROLE_A' /></user-service>",
"3.0.3", null)) "3.0.3", null))
.withMessageContaining( .withMessageContaining(
"You cannot use any XSD older than spring-security-7.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd"); "You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd");
} }
// SEC-1868 // SEC-1868

View File

@ -197,7 +197,7 @@ public class NamespaceHttpTests {
// @formatter:off // @formatter:off
this.mockMvc.perform(get("/")) this.mockMvc.perform(get("/"))
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\", charset=\"UTF-8\"")); .andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
// @formatter:on // @formatter:on
} }

View File

@ -222,8 +222,7 @@ public class WebSecurityConfigurationTests {
// SEC-2773 // SEC-2773
@Test @Test
public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationThenIsStatic() { public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationThenIsStatic() {
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
(Class<?>[]) null);
assertThat(Modifier.isStatic(method.getModifiers())).isTrue(); assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
} }

View File

@ -16,7 +16,6 @@
package org.springframework.security.config.annotation.web.configurers; package org.springframework.security.config.annotation.web.configurers;
import jakarta.servlet.http.HttpServletRequest;
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;
@ -24,8 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@ -37,14 +34,11 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication; import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication;
@ -107,45 +101,6 @@ public class AnonymousConfigurerTests {
this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("myAnonymousUser")); this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("myAnonymousUser"));
} }
@Test
public void anonymousAuthenticationWhenUsingAuthenticationDetailsSourceRefThenMatchesNamespace() throws Exception {
this.spring.register(AuthenticationDetailsSourceAnonymousConfig.class).autowire();
AuthenticationDetailsSource<HttpServletRequest, ?> source = this.spring.getContext()
.getBean(AuthenticationDetailsSource.class);
this.mockMvc.perform(get("/"));
verify(source).buildDetails(any(HttpServletRequest.class));
}
@Configuration
@EnableWebSecurity
@EnableWebMvc
static class AuthenticationDetailsSourceAnonymousConfig {
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = mock(
AuthenticationDetailsSource.class);
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.anonymous((anonymous) -> anonymous
.withObjectPostProcessor(new ObjectPostProcessor<AnonymousAuthenticationFilter>() {
@Override
public <O extends AnonymousAuthenticationFilter> O postProcess(O object) {
object.setAuthenticationDetailsSource(
AuthenticationDetailsSourceAnonymousConfig.this.authenticationDetailsSource);
return object;
}
})).build();
}
@Bean
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource() {
return this.authenticationDetailsSource;
}
}
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableWebMvc @EnableWebMvc

View File

@ -1201,7 +1201,6 @@ public class HeadersConfigurerTests {
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@SuppressWarnings("removal")
static class PermissionsPolicyConfig { static class PermissionsPolicyConfig {
@Bean @Bean
@ -1222,7 +1221,6 @@ public class HeadersConfigurerTests {
static class PermissionsPolicyStringConfig { static class PermissionsPolicyStringConfig {
@Bean @Bean
@SuppressWarnings("removal")
SecurityFilterChain filterChain(HttpSecurity http) throws Exception { SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off // @formatter:off
http http
@ -1237,7 +1235,6 @@ public class HeadersConfigurerTests {
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@SuppressWarnings("removal")
static class PermissionsPolicyInvalidConfig { static class PermissionsPolicyInvalidConfig {
@Bean @Bean
@ -1255,7 +1252,6 @@ public class HeadersConfigurerTests {
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@SuppressWarnings("removal")
static class PermissionsPolicyInvalidStringConfig { static class PermissionsPolicyInvalidStringConfig {
@Bean @Bean

View File

@ -103,7 +103,7 @@ public class HttpBasicConfigurerTests {
// @formatter:off // @formatter:off
this.mvc.perform(get("/")) this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\", charset=\"UTF-8\"")); .andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on // @formatter:on
} }
@ -114,7 +114,7 @@ public class HttpBasicConfigurerTests {
// @formatter:off // @formatter:off
this.mvc.perform(get("/")) this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\", charset=\"UTF-8\"")); .andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on // @formatter:on
} }

View File

@ -71,7 +71,7 @@ public class NamespaceHttpBasicTests {
// @formatter:off // @formatter:off
this.mvc.perform(requestWithInvalidPassword) this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\", charset=\"UTF-8\"")); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
// @formatter:on // @formatter:on
MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password")); MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password"));
this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound()); this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound());
@ -85,7 +85,7 @@ public class NamespaceHttpBasicTests {
// @formatter:off // @formatter:off
this.mvc.perform(requestWithInvalidPassword) this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\", charset=\"UTF-8\"")); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
// @formatter:on // @formatter:on
MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password")); MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password"));
this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound()); this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound());
@ -101,7 +101,7 @@ public class NamespaceHttpBasicTests {
// @formatter:off // @formatter:off
this.mvc.perform(requestWithInvalidPassword) this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\", charset=\"UTF-8\"")); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
// @formatter:on // @formatter:on
} }
@ -112,7 +112,7 @@ public class NamespaceHttpBasicTests {
// @formatter:off // @formatter:off
this.mvc.perform(requestWithInvalidPassword) this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\", charset=\"UTF-8\"")); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
// @formatter:on // @formatter:on
} }

View File

@ -1257,7 +1257,6 @@ public class OAuth2AuthorizationCodeGrantTests {
} }
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository( JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
jdbcOperations); jdbcOperations);

View File

@ -561,7 +561,6 @@ public class OAuth2ClientCredentialsGrantTests {
} }
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository( JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
jdbcOperations); jdbcOperations);

View File

@ -411,30 +411,6 @@ public class OAuth2ClientRegistrationTests {
.isCloseTo(expectedSecretExpiryDate, allowedDelta); .isCloseTo(expectedSecretExpiryDate, allowedDelta);
} }
@Test
public void requestWhenClientRegistersWithCustomTokenSettingsThenSavedToRegisteredClient() throws Exception {
this.spring.register(CustomTokenSettingsConfiguration.class).autowire();
// @formatter:off
OAuth2ClientRegistration clientRegistration = OAuth2ClientRegistration.builder()
.clientName("client-name")
.redirectUri("https://client.example.com")
.grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
.grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
.scope("scope1")
.scope("scope2")
.build();
// @formatter:on
OAuth2ClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
RegisteredClient registeredClient = this.registeredClientRepository
.findByClientId(clientRegistrationResponse.getClientId());
assertThat(registeredClient).isNotNull();
assertThat(registeredClient.getTokenSettings().getAccessTokenTimeToLive()).isEqualTo(Duration.ofMinutes(60));
}
private OAuth2ClientRegistration registerClient(OAuth2ClientRegistration clientRegistration) throws Exception { private OAuth2ClientRegistration registerClient(OAuth2ClientRegistration clientRegistration) throws Exception {
// ***** (1) Obtain the "initial" access token used for registering the client // ***** (1) Obtain the "initial" access token used for registering the client
@ -624,44 +600,6 @@ public class OAuth2ClientRegistrationTests {
} }
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
static class CustomTokenSettingsConfiguration extends AuthorizationServerConfiguration {
// @formatter:off
@Bean
@Override
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.oauth2AuthorizationServer((authorizationServer) ->
authorizationServer
.clientRegistrationEndpoint((clientRegistration) ->
clientRegistration
.authenticationProviders(configureClientRegistrationConverters())
)
)
.authorizeHttpRequests((authorize) ->
authorize.anyRequest().authenticated()
);
return http.build();
}
// @formatter:on
private Consumer<List<AuthenticationProvider>> configureClientRegistrationConverters() {
// @formatter:off
return (authenticationProviders) ->
authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof OAuth2ClientRegistrationAuthenticationProvider provider) {
OAuth2ClientRegistrationRegisteredClientConverter clientRegistrationRegisteredClientConverter = new OAuth2ClientRegistrationRegisteredClientConverter();
clientRegistrationRegisteredClientConverter.setTokenSettingsCustomizer((tokenSettings) -> tokenSettings.accessTokenTimeToLive(Duration.ofMinutes(60)));
provider.setRegisteredClientConverter(clientRegistrationRegisteredClientConverter);
}
});
// @formatter:on
}
}
@EnableWebSecurity @EnableWebSecurity
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class OpenClientRegistrationConfiguration extends AuthorizationServerConfiguration { static class OpenClientRegistrationConfiguration extends AuthorizationServerConfiguration {
@ -709,7 +647,6 @@ public class OAuth2ClientRegistrationTests {
// @formatter:on // @formatter:on
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
RegisteredClientParametersMapper registeredClientParametersMapper = new RegisteredClientParametersMapper(); RegisteredClientParametersMapper registeredClientParametersMapper = new RegisteredClientParametersMapper();

View File

@ -359,7 +359,7 @@ public class OAuth2DeviceCodeGrantTests {
} }
@Test @Test
public void requestWhenDeviceAuthorizationConsentRequestUnauthenticatedThenUnauthorized() throws Exception { public void requestWhenDeviceAuthorizationConsentRequestUnauthenticatedThenBadRequest() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire(); this.spring.register(AuthorizationServerConfiguration.class).autowire();
// @formatter:off // @formatter:off
@ -392,7 +392,7 @@ public class OAuth2DeviceCodeGrantTests {
// @formatter:off // @formatter:off
this.mvc.perform(post(DEFAULT_DEVICE_VERIFICATION_ENDPOINT_URI) this.mvc.perform(post(DEFAULT_DEVICE_VERIFICATION_ENDPOINT_URI)
.params(parameters)) .params(parameters))
.andExpect(status().isUnauthorized()); .andExpect(status().isBadRequest());
// @formatter:on // @formatter:on
} }

View File

@ -469,7 +469,6 @@ public class OAuth2RefreshTokenGrantTests {
} }
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository( JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
jdbcOperations); jdbcOperations);

View File

@ -515,7 +515,6 @@ public class OAuth2TokenIntrospectionTests {
} }
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository( JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
jdbcOperations); jdbcOperations);

View File

@ -318,7 +318,6 @@ public class OAuth2TokenRevocationTests {
} }
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository( JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
jdbcOperations); jdbcOperations);

View File

@ -778,7 +778,6 @@ public class OidcClientRegistrationTests {
// @formatter:on // @formatter:on
@Bean @Bean
@SuppressWarnings("removal")
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
RegisteredClientParametersMapper registeredClientParametersMapper = new RegisteredClientParametersMapper(); RegisteredClientParametersMapper registeredClientParametersMapper = new RegisteredClientParametersMapper();

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