mirror of
https://github.com/spring-projects/spring-security.git
synced 2026-03-06 19:54:32 +00:00
Compare commits
187 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56055605cd | ||
|
|
de3c72735e | ||
|
|
96bf048dd2 | ||
|
|
07297e7a80 | ||
|
|
b1f4deafe6 | ||
|
|
9893048ec9 | ||
|
|
e17d85e460 | ||
|
|
94829a1551 | ||
|
|
4f97217f68 | ||
|
|
4907d56a04 | ||
|
|
fdaa883fb7 | ||
|
|
f12036db05 | ||
|
|
b308c74c5e | ||
|
|
fbd9880a33 | ||
|
|
f14d2d2242 | ||
|
|
5e38c2aa88 | ||
|
|
7b5c502a97 | ||
|
|
e7bf4b561c | ||
|
|
41e3aeb246 | ||
|
|
89260a3a9c | ||
|
|
a84b506196 | ||
|
|
57434fc597 | ||
|
|
a01c0d003c | ||
|
|
20a7f96062 | ||
|
|
706b059ea8 | ||
|
|
f8d58fb267 | ||
|
|
7c49e0b457 | ||
|
|
2ac079dd1a | ||
|
|
04b270a0a3 | ||
|
|
7e4a926527 | ||
|
|
ea3b112bea | ||
|
|
17776e4738 | ||
|
|
1261c229a3 | ||
|
|
25ccb1fd70 | ||
|
|
587ac2cbad | ||
|
|
498b0cb59c | ||
|
|
b05b25f2d6 | ||
|
|
a5c0113ff0 | ||
|
|
bafd4034a0 | ||
|
|
ca34ec26d8 | ||
|
|
30dd328272 | ||
|
|
9f9bc0f729 | ||
|
|
9ce2d76508 | ||
|
|
0bb697c4a7 | ||
|
|
fb84e24893 | ||
|
|
b19e0e1ff3 | ||
|
|
c869565ab6 | ||
|
|
6118557b3e | ||
|
|
b9f974b18f | ||
|
|
e43275d1db | ||
|
|
18995c89ee | ||
|
|
0c42016781 | ||
|
|
1575610d49 | ||
|
|
3a14745d92 | ||
|
|
bd51ecd691 | ||
|
|
c29af014f4 | ||
|
|
4501ae7d1c | ||
|
|
48112d3d74 | ||
|
|
b8735abb63 | ||
|
|
50caf0cb28 | ||
|
|
7c3c8bbdcb | ||
|
|
b7dbb12c66 | ||
|
|
731848d5d3 | ||
|
|
eb25bbaa24 | ||
|
|
68a02ff176 | ||
|
|
ee97c83042 | ||
|
|
6304ea78cc | ||
|
|
10b835693c | ||
|
|
ba12f5e6d0 | ||
|
|
f37a706d62 | ||
|
|
e30d9240c9 | ||
|
|
c208410a91 | ||
|
|
aabc9fc1cc | ||
|
|
d3474e704f | ||
|
|
b48967eebc | ||
|
|
522c48b3b5 | ||
|
|
9cc3161055 | ||
|
|
6898de8003 | ||
|
|
1dae9aa459 | ||
|
|
4b0be84a0e | ||
|
|
73ee893d98 | ||
|
|
bec25edeb0 | ||
|
|
4d43edfb20 | ||
|
|
9f9699f8a5 | ||
|
|
6d4726bfb7 | ||
|
|
d31ca7a758 | ||
|
|
ac06067d02 | ||
|
|
9f1381c382 | ||
|
|
f700aeac0f | ||
|
|
41a8d6aca5 | ||
|
|
e81c64b94d | ||
|
|
0c394696ce | ||
|
|
62d1bc86e3 | ||
|
|
a4cadb5cc5 | ||
|
|
701736da5d | ||
|
|
9e5a425859 | ||
|
|
1ab17d941a | ||
|
|
53300be8d7 | ||
|
|
d5ba9dcada | ||
|
|
fa87c78edb | ||
|
|
f1e367f93d | ||
|
|
4d0627e6c0 | ||
|
|
3106f2be7b | ||
|
|
b3e5f09eb3 | ||
|
|
e1436c39f0 | ||
|
|
311235f39e | ||
|
|
fec988c82d | ||
|
|
17b434c1c1 | ||
|
|
b451739b5c | ||
|
|
0bb65411be | ||
|
|
d29c984881 | ||
|
|
cfb3bf38d8 | ||
|
|
151bcf3b0b | ||
|
|
1116241ee3 | ||
|
|
d87dc9ae57 | ||
|
|
ea1b3d819b | ||
|
|
2eb948d9b5 | ||
|
|
881ddf796a | ||
|
|
f2aef5168c | ||
|
|
ac556a45f9 | ||
|
|
c8731a8dc0 | ||
|
|
d62cce5bfb | ||
|
|
eca68b6cb3 | ||
|
|
3e60eeb74c | ||
|
|
21978cab22 | ||
|
|
2dd2863550 | ||
|
|
1fdfd45782 | ||
|
|
0dc1aa1126 | ||
|
|
3cc707621f | ||
|
|
f8ac095d48 | ||
|
|
d65625e399 | ||
|
|
18068c9099 | ||
|
|
a539f056f7 | ||
|
|
2b04177151 | ||
|
|
a4a6e9124c | ||
|
|
b21159f453 | ||
|
|
6f7c8cb352 | ||
|
|
5973a66bb1 | ||
|
|
3e3eeda560 | ||
|
|
cc6a005aa5 | ||
|
|
d4589c0fcb | ||
|
|
e2486a2590 | ||
|
|
dbf7f4cfe5 | ||
|
|
f27738c1f8 | ||
|
|
8d76ae0844 | ||
|
|
73b055baa9 | ||
|
|
5194826606 | ||
|
|
fc48088759 | ||
|
|
d528be38bb | ||
|
|
da0cd0bc68 | ||
|
|
410812c5bc | ||
|
|
329d9e2dfd | ||
|
|
dc8ed8b168 | ||
|
|
17933ddab3 | ||
|
|
deb6416c93 | ||
|
|
9323775c5f | ||
|
|
4cc5f543ab | ||
|
|
67bc1d8d4a | ||
|
|
17b5cdde55 | ||
|
|
e91b098c7c | ||
|
|
21bef947b0 | ||
|
|
6fcca39500 | ||
|
|
544f635e9b | ||
|
|
e4dcffae8a | ||
|
|
f52f097a4d | ||
|
|
1cd145d026 | ||
|
|
3c55f057b1 | ||
|
|
6d2a414022 | ||
|
|
58df50c3a3 | ||
|
|
79156b2387 | ||
|
|
4aa9ff99f5 | ||
|
|
9b978ae70b | ||
|
|
3abb69d5a9 | ||
|
|
6c2b2a7611 | ||
|
|
0fab34f359 | ||
|
|
73dff1f8a3 | ||
|
|
e5906d97ea | ||
|
|
c0da8b390b | ||
|
|
ffe73b4920 | ||
|
|
f0ffda89e0 | ||
|
|
746c6e124e | ||
|
|
08e5b375ac | ||
|
|
123a2d79cf | ||
|
|
f9c32afb6f | ||
|
|
0c3e483432 | ||
|
|
3d61276a1a | ||
|
|
0d3a5d210a |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@ -64,6 +64,7 @@ updates:
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
- dependency-name: io.spring.nullability:*
|
||||
- dependency-name: org.python:jython
|
||||
- dependency-name: org.apache.directory.server:*
|
||||
- dependency-name: org.apache.directory.shared:*
|
||||
|
||||
2
.github/workflows/check-snapshots.yml
vendored
2
.github/workflows/check-snapshots.yml
vendored
@ -14,7 +14,7 @@ permissions:
|
||||
jobs:
|
||||
snapshot-test:
|
||||
name: Test Against Snapshots
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@7d42d82298553f123a9dad622e0eac725aaf52ef # v1.0.13
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@729fed56d42122f88583aff1be35c0800b7d77e9 # v1.0.14
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
|
||||
@ -55,7 +55,7 @@ jobs:
|
||||
release-repo-url: https://repo1.maven.org/maven2
|
||||
artifact-path: org/springframework/security/spring-security-core
|
||||
slack-announcing-id: spring-security-announcing
|
||||
java-version: 25:q
|
||||
java-version: 25
|
||||
secrets: inherit
|
||||
send-notification:
|
||||
name: Send Notification
|
||||
|
||||
@ -9,6 +9,7 @@ permissions:
|
||||
jobs:
|
||||
upgrade_wrapper:
|
||||
name: Execution
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Git configuration
|
||||
|
||||
2
.github/workflows/pr-build-workflow.yml
vendored
2
.github/workflows/pr-build-workflow.yml
vendored
@ -34,7 +34,7 @@ jobs:
|
||||
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
|
||||
- name: Upload Docs
|
||||
id: upload
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: docs
|
||||
path: docs/build/site
|
||||
|
||||
@ -12,8 +12,9 @@ permissions:
|
||||
|
||||
jobs:
|
||||
update-antora-ui-spring:
|
||||
runs-on: ubuntu-latest
|
||||
name: Update on Supported Branches
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
branch: [ '6.5.x', '7.0.x', 'main' ]
|
||||
@ -25,8 +26,9 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
antora-file-path: 'docs/antora-playbook.yml'
|
||||
update-antora-ui-spring-docs-build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Update on docs-build
|
||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf
|
||||
name: Update
|
||||
|
||||
21
README.adoc
21
README.adoc
@ -68,6 +68,27 @@ The https://github.com/spring-projects/spring-security/tree/docs-build[playbook
|
||||
|
||||
Discover more commands with `./gradlew tasks`.
|
||||
|
||||
=== IDE setup (IntelliJ)
|
||||
|
||||
No special steps are needed to open Spring Security in IntelliJ.
|
||||
|
||||
=== IDE setup (Eclipse and VS Code)
|
||||
|
||||
To work in Eclipse or VS Code, first generate Eclipse metadata so you can import the project into Eclipse or VS Code:
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
./gradlew cleanEclipse eclipse
|
||||
----
|
||||
|
||||
If you have not built the project yet, run `./gradlew publishToMavenLocal` first so dependencies are resolved.
|
||||
|
||||
*VS Code:* Open the repository root as a folder. The repository includes `.vscode/settings.json` which disables automatic Gradle import so that the generated Eclipse metadata (`.classpath`, `.project`) is used. Do not use the Gradle for Java extension to import the project.
|
||||
|
||||
*Eclipse:* File → Import → General → Existing Projects into Workspace, then select the repository root.
|
||||
|
||||
The build uses a custom Eclipse plugin to work around Gradle dependency cycles that confuse IDE metadata generation. You may see Eclipse warnings about `xml-apis` from some test dependencies; those are excluded in the build and can be ignored.
|
||||
|
||||
== Getting Support
|
||||
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
|
||||
https://spring.io/support[Commercial support] is available too.
|
||||
|
||||
@ -31,6 +31,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Sources method security metadata from major JSR 250 security annotations.
|
||||
@ -108,7 +109,7 @@ public class Jsr250MethodSecurityMetadataSource extends AbstractFallbackMethodSe
|
||||
if (role == null) {
|
||||
return role;
|
||||
}
|
||||
if (this.defaultRolePrefix == null || this.defaultRolePrefix.length() == 0) {
|
||||
if (!StringUtils.hasLength(this.defaultRolePrefix)) {
|
||||
return role;
|
||||
}
|
||||
if (role.startsWith(this.defaultRolePrefix)) {
|
||||
|
||||
@ -23,6 +23,7 @@ import java.util.Locale;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
@ -73,7 +74,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
* be overridden using a null check in the expression itself).
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
|
||||
public boolean hasPermission(Authentication authentication, @Nullable Object domainObject, Object permission) {
|
||||
if (domainObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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;
|
||||
2
acl/src/main/resources/META-INF/spring/aot.factories
Normal file
2
acl/src/main/resources/META-INF/spring/aot.factories
Normal file
@ -0,0 +1,2 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||
org.springframework.security.acls.aot.hint.AclRuntimeHints
|
||||
@ -8,3 +8,4 @@ tasks.withType(JavaCompile) {
|
||||
tasks.withType(KotlinCompile) {
|
||||
kotlinOptions.allWarningsAsErrors = true
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ import org.springframework.util.Assert;
|
||||
* and using the current URL minus the artifact and the corresponding value.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Ngoc Nhan
|
||||
*/
|
||||
final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
implements ServiceAuthenticationDetails {
|
||||
@ -74,10 +75,9 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) {
|
||||
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails that)) {
|
||||
return false;
|
||||
}
|
||||
ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj;
|
||||
return this.serviceUrl.equals(that.getServiceUrl());
|
||||
}
|
||||
|
||||
@ -101,7 +101,11 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
/**
|
||||
* If present, removes the artifactParameterName and the corresponding value from the
|
||||
* query String.
|
||||
* @param request
|
||||
* @param request the current {@link HttpServletRequest} to obtain the
|
||||
* {@link #getServiceUrl()} from.
|
||||
* @param artifactPattern the {@link Pattern} that will be used to clean up the query
|
||||
* string from containing the artifact name and value. This can be created using
|
||||
* {@link #createArtifactPattern(String)}.
|
||||
* @return the query String minus the artifactParameterName and the corresponding
|
||||
* value.
|
||||
*/
|
||||
@ -111,7 +115,7 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
return null;
|
||||
}
|
||||
String result = artifactPattern.matcher(query).replaceFirst("");
|
||||
if (result.length() == 0) {
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// strip off the trailing & only if the artifact was the first query param
|
||||
@ -122,8 +126,9 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
|
||||
* Creates a {@link Pattern} that can be passed into the constructor. This allows the
|
||||
* {@link Pattern} to be reused for every instance of
|
||||
* {@link DefaultServiceAuthenticationDetails}.
|
||||
* @param artifactParameterName
|
||||
* @return
|
||||
* @param artifactParameterName the artifactParameterName that is removed from the
|
||||
* current URL. The result becomes the service url. Cannot be null or an empty String.
|
||||
* @return a {@link Pattern}
|
||||
*/
|
||||
static Pattern createArtifactPattern(String artifactParameterName) {
|
||||
Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length");
|
||||
|
||||
@ -5,6 +5,7 @@ apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'trang'
|
||||
apply plugin: 'security-kotlin'
|
||||
apply plugin: 'test-compile-target-jdk25'
|
||||
apply plugin: 'compile-warnings-error'
|
||||
apply plugin: 'javadoc-warnings-error'
|
||||
|
||||
configurations {
|
||||
|
||||
@ -36,6 +36,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
@ -302,6 +303,7 @@ public class AuthenticationConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Contract("!null -> !null; null -> null")
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return getPasswordEncoder().encode(rawPassword);
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
@ -293,6 +294,7 @@ class HttpSecurityConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Contract("!null -> !null; null -> null")
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return getPasswordEncoder().encode(rawPassword);
|
||||
}
|
||||
|
||||
@ -521,8 +521,10 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
public OpaqueTokenConfigurer introspectionUri(String introspectionUri) {
|
||||
Assert.notNull(introspectionUri, "introspectionUri cannot be null");
|
||||
this.introspectionUri = introspectionUri;
|
||||
this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
|
||||
this.clientSecret);
|
||||
this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri)
|
||||
.clientId(this.clientId)
|
||||
.clientSecret(this.clientSecret)
|
||||
.build();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -531,8 +533,10 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
Assert.notNull(clientSecret, "clientSecret cannot be null");
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
|
||||
this.clientSecret);
|
||||
this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri)
|
||||
.clientId(this.clientId)
|
||||
.clientSecret(this.clientSecret)
|
||||
.build();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@ -124,6 +124,10 @@ class AuthorizationFilterParser implements BeanDefinitionParser {
|
||||
List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
for (Element interceptMessage : interceptMessages) {
|
||||
String accessExpression = interceptMessage.getAttribute(ATT_ACCESS);
|
||||
if (!StringUtils.hasText(accessExpression)) {
|
||||
parserContext.getReaderContext().error("access attribute cannot be empty or null", interceptMessage);
|
||||
continue;
|
||||
}
|
||||
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(WebExpressionAuthorizationManager.class);
|
||||
authorizationManager.addPropertyReference("expressionHandler", expressionHandlerRef);
|
||||
|
||||
@ -142,10 +142,11 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||
ManagedMap<BeanMetadataElement, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<>();
|
||||
for (Element urlElt : urlElts) {
|
||||
String access = urlElt.getAttribute(ATT_ACCESS);
|
||||
String path = urlElt.getAttribute(ATT_PATTERN);
|
||||
if (!StringUtils.hasText(access)) {
|
||||
parserContext.getReaderContext().error("access attribute cannot be empty or null", urlElt);
|
||||
continue;
|
||||
}
|
||||
String path = urlElt.getAttribute(ATT_PATTERN);
|
||||
String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF);
|
||||
boolean hasMatcherRef = StringUtils.hasText(matcherRef);
|
||||
if (!hasMatcherRef && !StringUtils.hasText(path)) {
|
||||
|
||||
@ -23,9 +23,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
@ -44,25 +42,18 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.vote.ConsensusBased;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.config.http.MessageMatcherFactoryBean;
|
||||
import org.springframework.security.config.web.messaging.PathPatternMessageMatcherBuilderFactoryBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
|
||||
import org.springframework.security.messaging.access.expression.MessageAuthorizationContextSecurityExpressionHandler;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionAuthorizationManager;
|
||||
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
|
||||
import org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor;
|
||||
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
|
||||
@ -75,7 +66,6 @@ import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatche
|
||||
import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
|
||||
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@ -219,9 +209,15 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
String messageType = interceptMessage.getAttribute(TYPE_ATTR);
|
||||
BeanDefinition matcher = createMatcher(matcherPattern, messageType, parserContext, interceptMessage);
|
||||
BeanDefinitionBuilder authorizationManager = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(ExpressionBasedAuthorizationManager.class);
|
||||
.rootBeanDefinition(MessageExpressionAuthorizationManager.class);
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
authorizationManager.addConstructorArgReference(expressionHandlerRef);
|
||||
BeanDefinitionBuilder authorizationManagerBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MessageExpressionAuthorizationManager.class);
|
||||
authorizationManagerBuilder.setFactoryMethod("withSecurityExpressionHandler");
|
||||
authorizationManagerBuilder.addConstructorArgReference(expressionHandlerRef);
|
||||
String authorizationManagerBuilderRef = context
|
||||
.registerWithGeneratedName(authorizationManagerBuilder.getBeanDefinition());
|
||||
authorizationManager.setFactoryMethodOnBean("expression", authorizationManagerBuilderRef);
|
||||
}
|
||||
authorizationManager.addConstructorArgValue(accessExpression);
|
||||
matcherToExpression.put(matcher, authorizationManager.getBeanDefinition());
|
||||
@ -439,35 +435,6 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
|
||||
}
|
||||
|
||||
private static final class ExpressionBasedAuthorizationManager
|
||||
implements AuthorizationManager<MessageAuthorizationContext<?>> {
|
||||
|
||||
private final SecurityExpressionHandler<MessageAuthorizationContext<?>> expressionHandler;
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
private ExpressionBasedAuthorizationManager(String expression) {
|
||||
this(new MessageAuthorizationContextSecurityExpressionHandler(), expression);
|
||||
}
|
||||
|
||||
private ExpressionBasedAuthorizationManager(
|
||||
SecurityExpressionHandler<MessageAuthorizationContext<?>> expressionHandler, String expression) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
Assert.notNull(expression, "expression cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
|
||||
MessageAuthorizationContext<?> object) {
|
||||
EvaluationContext context = this.expressionHandler.createEvaluationContext(authentication, object);
|
||||
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, context);
|
||||
return new AuthorizationDecision(granted);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MessageMatcherDelegatingAuthorizationManagerFactory {
|
||||
|
||||
private static AuthorizationManager<Message<?>> createMessageMatcherDelegatingAuthorizationManager(
|
||||
|
||||
@ -286,7 +286,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
||||
if (factoryOfRequestAuthorizationContext != null) {
|
||||
return factoryOfRequestAuthorizationContext
|
||||
}
|
||||
val factoryOfObjectType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory::class.java, Object::class.java)
|
||||
val factoryOfObjectType = ResolvableType.forClassWithGenerics(AuthorizationManagerFactory::class.java, Any::class.java)
|
||||
val factoryOfAny = context.getBeanProvider<AuthorizationManagerFactory<Any>>(factoryOfObjectType).getIfUnique()
|
||||
if (factoryOfAny != null) {
|
||||
return factoryOfAny
|
||||
@ -303,20 +303,20 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
||||
return defaultFactory
|
||||
}
|
||||
|
||||
private fun resolveRolePrefix(context: ApplicationContext): String {
|
||||
private fun resolveRolePrefix(context: ApplicationContext): String? {
|
||||
val beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults::class.java)
|
||||
if (beanNames.isNotEmpty()) {
|
||||
return context.getBean(GrantedAuthorityDefaults::class.java).rolePrefix
|
||||
}
|
||||
return "ROLE_";
|
||||
return null
|
||||
}
|
||||
|
||||
private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy {
|
||||
private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy? {
|
||||
val beanNames = context.getBeanNamesForType(RoleHierarchy::class.java)
|
||||
if (beanNames.isNotEmpty()) {
|
||||
return context.getBean(RoleHierarchy::class.java)
|
||||
}
|
||||
return NullRoleHierarchy()
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -37,9 +37,11 @@ class HeadersDsl {
|
||||
private var cacheControl: ((HeadersConfigurer<HttpSecurity>.CacheControlConfig) -> Unit)? = null
|
||||
private var hsts: ((HeadersConfigurer<HttpSecurity>.HstsConfig) -> Unit)? = null
|
||||
private var frameOptions: ((HeadersConfigurer<HttpSecurity>.FrameOptionsConfig) -> Unit)? = null
|
||||
@Suppress("DEPRECATION")
|
||||
private var hpkp: ((HeadersConfigurer<HttpSecurity>.HpkpConfig) -> Unit)? = null
|
||||
private var contentSecurityPolicy: ((HeadersConfigurer<HttpSecurity>.ContentSecurityPolicyConfig) -> Unit)? = null
|
||||
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
|
||||
@Suppress("DEPRECATION")
|
||||
private var featurePolicyDirectives: String? = null
|
||||
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
|
||||
private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null
|
||||
@ -120,6 +122,7 @@ class HeadersDsl {
|
||||
* @deprecated see <a href="https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning">Certificate and Public Key Pinning</a> for more context
|
||||
*/
|
||||
@Deprecated(message = "as of 5.8 with no replacement")
|
||||
@Suppress("DEPRECATION")
|
||||
fun httpPublicKeyPinning(hpkpConfig: HttpPublicKeyPinningDsl.() -> Unit) {
|
||||
this.hpkp = HttpPublicKeyPinningDsl().apply(hpkpConfig).get()
|
||||
}
|
||||
@ -167,6 +170,7 @@ class HeadersDsl {
|
||||
* @param policyDirectives policyDirectives the security policy directive(s)
|
||||
*/
|
||||
@Deprecated("Use 'permissionsPolicy { }' instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
fun featurePolicy(policyDirectives: String) {
|
||||
this.featurePolicyDirectives = policyDirectives
|
||||
}
|
||||
|
||||
@ -614,6 +614,7 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
||||
* @see [RequiresChannelDsl]
|
||||
* @deprecated please use [redirectToHttps] instead
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated(message="since 6.5 use redirectToHttps instead")
|
||||
fun requiresChannel(requiresChannelConfiguration: RequiresChannelDsl.() -> Unit) {
|
||||
val requiresChannelCustomizer = RequiresChannelDsl().apply(requiresChannelConfiguration).get()
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.springframework.security.config.annotation.web
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
|
||||
@ -62,6 +62,7 @@ class X509Dsl {
|
||||
authenticationDetailsSource?.also { x509.authenticationDetailsSource(authenticationDetailsSource) }
|
||||
userDetailsService?.also { x509.userDetailsService(userDetailsService) }
|
||||
authenticationUserDetailsService?.also { x509.authenticationUserDetailsService(authenticationUserDetailsService) }
|
||||
@Suppress("DEPRECATION")
|
||||
subjectPrincipalRegex?.also { x509.subjectPrincipalRegex(subjectPrincipalRegex) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.springframework.security.config.annotation.web.headers
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
|
||||
@ -68,12 +68,11 @@ class SessionFixationDsl {
|
||||
internal fun get(): (SessionManagementConfigurer<HttpSecurity>.SessionFixationConfigurer) -> Unit {
|
||||
return { sessionFixation ->
|
||||
strategy?.also {
|
||||
when (strategy) {
|
||||
when (it) {
|
||||
SessionFixationStrategy.NEW -> sessionFixation.newSession()
|
||||
SessionFixationStrategy.MIGRATE -> sessionFixation.migrateSession()
|
||||
SessionFixationStrategy.CHANGE_ID -> sessionFixation.changeSessionId()
|
||||
SessionFixationStrategy.NONE -> sessionFixation.none()
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@ base64 =
|
||||
## Whether a string should be base64 encoded
|
||||
attribute base64 {xsd:boolean}
|
||||
request-matcher =
|
||||
## Defines the strategy use for matching incoming requests. Currently the options are 'mvc' (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
|
||||
attribute request-matcher {"mvc" | "ant" | "regex" | "ciRegex"}
|
||||
## Defines the strategy use for matching incoming requests. Currently the options are 'path' (for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions.
|
||||
attribute request-matcher {"path" | "regex" | "ciRegex"}
|
||||
port =
|
||||
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
|
||||
attribute port { xsd:nonNegativeInteger }
|
||||
|
||||
@ -27,15 +27,14 @@
|
||||
<xs:attributeGroup name="request-matcher">
|
||||
<xs:attribute name="request-matcher" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
|
||||
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="path"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
</xs:restriction>
|
||||
@ -1306,15 +1305,14 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="request-matcher">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
|
||||
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="path"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
</xs:restriction>
|
||||
@ -2474,15 +2472,14 @@
|
||||
<xs:attributeGroup name="filter-chain-map.attlist">
|
||||
<xs:attribute name="request-matcher">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
|
||||
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="path"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
</xs:restriction>
|
||||
@ -2580,15 +2577,14 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="request-matcher">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'mvc'
|
||||
(for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions
|
||||
and 'ciRegex' for case-insensitive regular expressions.
|
||||
<xs:documentation>Defines the strategy use for matching incoming requests. Currently the options are 'path'
|
||||
(for PathPatternRequestMatcher), 'regex' for regular expressions and 'ciRegex' for
|
||||
case-insensitive regular expressions.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="mvc"/>
|
||||
<xs:enumeration value="ant"/>
|
||||
<xs:enumeration value="path"/>
|
||||
<xs:enumeration value="regex"/>
|
||||
<xs:enumeration value="ciRegex"/>
|
||||
</xs:restriction>
|
||||
|
||||
@ -20,6 +20,7 @@ import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.Principal;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
@ -245,12 +246,15 @@ import org.springframework.security.web.savedrequest.SimpleSavedRequest;
|
||||
import org.springframework.security.web.server.firewall.ServerExchangeRejectedException;
|
||||
import org.springframework.security.web.session.HttpSessionCreatedEvent;
|
||||
import org.springframework.security.web.session.HttpSessionIdChangedEvent;
|
||||
import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
|
||||
import org.springframework.security.web.webauthn.api.Bytes;
|
||||
import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
|
||||
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
|
||||
import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
|
||||
@ -258,12 +262,17 @@ import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExte
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
|
||||
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialParameters;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
|
||||
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
|
||||
import org.springframework.security.web.webauthn.api.TestBytes;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials;
|
||||
@ -271,6 +280,7 @@ import org.springframework.security.web.webauthn.api.UserVerificationRequirement
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication;
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken;
|
||||
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
|
||||
import org.springframework.security.web.webauthn.management.TestPublicKeyCredentialRpEntities;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
final class SerializationSamples {
|
||||
@ -284,6 +294,14 @@ final class SerializationSamples {
|
||||
Authentication authentication = TestAuthentication.authenticated(user);
|
||||
SecurityContext securityContext = new SecurityContextImpl(authentication);
|
||||
|
||||
instancioByClassName.put(OneTimeTokenAuthenticationToken.class, () -> {
|
||||
@SuppressWarnings("removal")
|
||||
InstancioOfClassApi<?> instancio = Instancio.of(OneTimeTokenAuthenticationToken.class);
|
||||
instancio.supply(Select.all(OneTimeTokenAuthenticationToken.class),
|
||||
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("token")));
|
||||
return instancio;
|
||||
});
|
||||
|
||||
// oauth2-core
|
||||
generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create());
|
||||
generatorByClassName.put(OAuth2AuthorizationRequest.class,
|
||||
@ -597,8 +615,7 @@ final class SerializationSamples {
|
||||
token.setDetails(details);
|
||||
return token;
|
||||
});
|
||||
generatorByClassName.put(OneTimeTokenAuthenticationToken.class,
|
||||
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token")));
|
||||
|
||||
generatorByClassName.put(OneTimeTokenAuthentication.class,
|
||||
(r) -> applyDetails(new OneTimeTokenAuthentication("username", authentication.getAuthorities())));
|
||||
generatorByClassName.put(AccessDeniedException.class,
|
||||
@ -879,6 +896,36 @@ final class SerializationSamples {
|
||||
generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class,
|
||||
(r) -> new CredentialPropertiesOutput(true).getOutput());
|
||||
|
||||
AttestationConveyancePreference attestationConveyancePreference = AttestationConveyancePreference.DIRECT;
|
||||
ResidentKeyRequirement residentKeyRequirement = ResidentKeyRequirement.REQUIRED;
|
||||
AuthenticatorSelectionCriteria authenticatorSelectionCriteria = AuthenticatorSelectionCriteria.builder()
|
||||
.authenticatorAttachment(AuthenticatorAttachment.PLATFORM)
|
||||
.residentKey(residentKeyRequirement)
|
||||
.userVerification(UserVerificationRequirement.REQUIRED)
|
||||
.build();
|
||||
PublicKeyCredentialParameters publicKeyCredentialParameters = PublicKeyCredentialParameters.RS256;
|
||||
PublicKeyCredentialRpEntity publicKeyCredentialRpEntity = TestPublicKeyCredentialRpEntities.createRpEntity()
|
||||
.build();
|
||||
|
||||
generatorByClassName.put(AttestationConveyancePreference.class, (r) -> attestationConveyancePreference);
|
||||
generatorByClassName.put(ResidentKeyRequirement.class, (r) -> residentKeyRequirement);
|
||||
generatorByClassName.put(AuthenticatorSelectionCriteria.class, (r) -> authenticatorSelectionCriteria);
|
||||
generatorByClassName.put(COSEAlgorithmIdentifier.class, ((r) -> COSEAlgorithmIdentifier.RS256));
|
||||
generatorByClassName.put(PublicKeyCredentialParameters.class, (r) -> publicKeyCredentialParameters);
|
||||
generatorByClassName.put(PublicKeyCredentialRpEntity.class, (r) -> publicKeyCredentialRpEntity);
|
||||
generatorByClassName.put(PublicKeyCredentialCreationOptions.class,
|
||||
(o) -> TestPublicKeyCredentialCreationOptions.createPublicKeyCredentialCreationOptions()
|
||||
.extensions(inputs)
|
||||
.attestation(attestationConveyancePreference)
|
||||
.authenticatorSelection(authenticatorSelectionCriteria)
|
||||
.challenge(TestBytes.get())
|
||||
.excludeCredentials(List.of(descriptor))
|
||||
.rp(publicKeyCredentialRpEntity)
|
||||
.pubKeyCredParams(publicKeyCredentialParameters)
|
||||
.timeout(Duration.ofMinutes(5))
|
||||
.user(TestPublicKeyCredentialUserEntities.userEntity().id(TestBytes.get()).build())
|
||||
.build());
|
||||
|
||||
// One-Time Token
|
||||
DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user",
|
||||
Instant.now().plusSeconds(300));
|
||||
|
||||
@ -222,7 +222,8 @@ public class WebSecurityConfigurationTests {
|
||||
// SEC-2773
|
||||
@Test
|
||||
public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationThenIsStatic() {
|
||||
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
|
||||
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener",
|
||||
(Class<?>[]) null);
|
||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||
}
|
||||
|
||||
|
||||
@ -1201,6 +1201,7 @@ public class HeadersConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@SuppressWarnings("removal")
|
||||
static class PermissionsPolicyConfig {
|
||||
|
||||
@Bean
|
||||
@ -1221,6 +1222,7 @@ public class HeadersConfigurerTests {
|
||||
static class PermissionsPolicyStringConfig {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
@ -1235,6 +1237,7 @@ public class HeadersConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@SuppressWarnings("removal")
|
||||
static class PermissionsPolicyInvalidConfig {
|
||||
|
||||
@Bean
|
||||
@ -1252,6 +1255,7 @@ public class HeadersConfigurerTests {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@SuppressWarnings("removal")
|
||||
static class PermissionsPolicyInvalidStringConfig {
|
||||
|
||||
@Bean
|
||||
|
||||
@ -1257,6 +1257,7 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
@ -561,6 +561,7 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
@ -647,6 +647,7 @@ public class OAuth2ClientRegistrationTests {
|
||||
// @formatter:on
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
RegisteredClientParametersMapper registeredClientParametersMapper = new RegisteredClientParametersMapper();
|
||||
|
||||
@ -469,6 +469,7 @@ public class OAuth2RefreshTokenGrantTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
@ -515,6 +515,7 @@ public class OAuth2TokenIntrospectionTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
@ -318,6 +318,7 @@ public class OAuth2TokenRevocationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
@ -778,6 +778,7 @@ public class OidcClientRegistrationTests {
|
||||
// @formatter:on
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
RegisteredClientParametersMapper registeredClientParametersMapper = new RegisteredClientParametersMapper();
|
||||
|
||||
@ -633,6 +633,7 @@ public class OidcTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("removal")
|
||||
RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
|
||||
JdbcRegisteredClientRepository jdbcRegisteredClientRepository = new JdbcRegisteredClientRepository(
|
||||
jdbcOperations);
|
||||
|
||||
@ -337,6 +337,54 @@ public class InterceptUrlConfigTests {
|
||||
assertThat(this.spring.getContext().getBean(AuthorizationManager.class)).isNotNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* gh-18503
|
||||
*/
|
||||
@Test
|
||||
public void configWhenInterceptUrlMissingAccessThenException() {
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccess")).autowire())
|
||||
.withMessageContaining("access attribute cannot be empty or null");
|
||||
}
|
||||
|
||||
/**
|
||||
* gh-18503
|
||||
*/
|
||||
@Test
|
||||
public void configWhenInterceptUrlEmptyAccessThenException() {
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccess")).autowire())
|
||||
.withMessageContaining("access attribute cannot be empty or null");
|
||||
}
|
||||
|
||||
/**
|
||||
* gh-18503
|
||||
*/
|
||||
@Test
|
||||
public void configWhenInterceptUrlValidAccessThenLoads() {
|
||||
assertThatNoException().isThrownBy(() -> this.spring.configLocations(this.xml("ValidAccess")).autowire());
|
||||
}
|
||||
|
||||
/**
|
||||
* gh-18503
|
||||
*/
|
||||
@Test
|
||||
public void configWhenUseAuthorizationManagerFalseAndMissingAccessThenException() {
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> this.spring.configLocations(this.xml("MissingAccessLegacy")).autowire())
|
||||
.withMessageContaining("access attribute cannot be empty or null");
|
||||
}
|
||||
|
||||
/**
|
||||
* gh-18503
|
||||
*/
|
||||
@Test
|
||||
public void configWhenUseAuthorizationManagerFalseAndEmptyAccessThenException() {
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class)
|
||||
.isThrownBy(() -> this.spring.configLocations(this.xml("EmptyAccessLegacy")).autowire())
|
||||
.withMessageContaining("access attribute cannot be empty or null");
|
||||
}
|
||||
|
||||
private static RequestPostProcessor adminCredentials() {
|
||||
return httpBasic("admin", "password");
|
||||
}
|
||||
|
||||
@ -100,6 +100,7 @@ import static org.mockito.Mockito.verify;
|
||||
* {@link org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec}
|
||||
*/
|
||||
@ExtendWith({ SpringTestContextExtension.class })
|
||||
@SuppressWarnings("removal")
|
||||
public class OAuth2ResourceServerSpecTests {
|
||||
|
||||
private String expired = "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE1MzUwMzc4OTd9.jqZDDjfc2eysX44lHXEIr9XFd2S8vjIZHCccZU-dRWMRJNsQ1QN5VNnJGklqJBXJR4qgla6cmVqPOLkUHDb0sL0nxM5XuzQaG5ZzKP81RV88shFyAiT0fD-6nl1k-Fai-Fu-VkzSpNXgeONoTxDaYhdB-yxmgrgsApgmbOTE_9AcMk-FQDXQ-pL9kynccFGV0lZx4CA7cyknKN7KBxUilfIycvXODwgKCjj_1WddLTCNGYogJJSg__7NoxzqbyWd3udbHVjqYq7GsMMrGB4_2kBD4CkghOSNcRHbT_DIXowxfAVT7PAg7Q0E5ruZsr2zPZacEUDhJ6-wbvlA0FAOUg";
|
||||
|
||||
@ -167,6 +167,7 @@ public class OidcLogoutSpecTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void logoutWhenInvalidLogoutTokenThenBadRequest() {
|
||||
this.spring.register(WebServerConfig.class, OidcProviderConfig.class, DefaultConfig.class).autowire();
|
||||
this.test.get().uri("/token/logout").exchange().expectStatus().isUnauthorized();
|
||||
@ -209,6 +210,7 @@ public class OidcLogoutSpecTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void logoutWhenLogoutTokenSpecifiesOneSessionThenRemotelyInvalidatesOnlyThatSession() throws Exception {
|
||||
this.spring.register(WebServerConfig.class, OidcProviderConfig.class, DefaultConfig.class).autowire();
|
||||
String registrationId = this.clientRegistration.getRegistrationId();
|
||||
@ -252,6 +254,7 @@ public class OidcLogoutSpecTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void logoutWhenRemoteLogoutUriThenUses() {
|
||||
this.spring.register(WebServerConfig.class, OidcProviderConfig.class, LogoutUriConfig.class).autowire();
|
||||
String registrationId = this.clientRegistration.getRegistrationId();
|
||||
@ -302,6 +305,7 @@ public class OidcLogoutSpecTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void logoutWhenDifferentCookieNameThenUses() {
|
||||
this.spring.register(OidcProviderConfig.class, CookieConfig.class).autowire();
|
||||
String registrationId = this.clientRegistration.getRegistrationId();
|
||||
@ -325,6 +329,7 @@ public class OidcLogoutSpecTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void logoutWhenRemoteLogoutFailsThenReportsPartialLogout() {
|
||||
this.spring.register(WebServerConfig.class, OidcProviderConfig.class, WithBrokenLogoutConfig.class).autowire();
|
||||
ServerLogoutHandler logoutHandler = this.spring.getContext().getBean(ServerLogoutHandler.class);
|
||||
|
||||
@ -737,6 +737,7 @@ public class ServerHttpSecurityTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void resourcesWhenLoginPageConfiguredThenServesCss() {
|
||||
this.http.formLogin(withDefaults());
|
||||
this.http.authenticationManager(this.authenticationManager);
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
|
||||
* Copyright 2004-present the original author or authors.
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@file:Suppress("DEPRECATION", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http request-matcher="ant" use-authorization-manager="false">
|
||||
<http request-matcher="path" use-authorization-manager="false">
|
||||
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
|
||||
<http-basic/>
|
||||
</http>
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http request-matcher="ant">
|
||||
<http request-matcher="path">
|
||||
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
|
||||
<http-basic/>
|
||||
</http>
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http>
|
||||
<intercept-url pattern="/admin/**" access="" />
|
||||
</http>
|
||||
|
||||
<user-service>
|
||||
<user name="user" password="{noop}password" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
|
||||
</b:beans>
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http use-authorization-manager="false">
|
||||
<intercept-url pattern="/admin/**" access=""/>
|
||||
</http>
|
||||
|
||||
<user-service>
|
||||
<user name="user" password="{noop}password" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
|
||||
</b:beans>
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http>
|
||||
<intercept-url pattern="/admin/**"/>
|
||||
</http>
|
||||
|
||||
<user-service>
|
||||
<user name="user" password="{noop}password" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
|
||||
</b:beans>
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http use-authorization-manager="false">
|
||||
<intercept-url pattern="/admin/**"/>
|
||||
</http>
|
||||
|
||||
<user-service>
|
||||
<user name="user" password="{noop}password" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
|
||||
</b:beans>
|
||||
@ -27,7 +27,7 @@
|
||||
http://www.springframework.org/schema/mvc
|
||||
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
<http auto-config="true" request-matcher="mvc" use-authorization-manager="false">
|
||||
<http auto-config="true" request-matcher="path" use-authorization-manager="false">
|
||||
<intercept-url pattern="/path" access="denyAll"/>
|
||||
<http-basic/>
|
||||
</http>
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
http://www.springframework.org/schema/mvc
|
||||
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
<http auto-config="true" request-matcher="mvc">
|
||||
<http auto-config="true" request-matcher="path">
|
||||
<intercept-url pattern="/path" access="denyAll"/>
|
||||
<http-basic/>
|
||||
</http>
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
http://www.springframework.org/schema/mvc
|
||||
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
<http auto-config="true" request-matcher="mvc" use-authorization-manager="false">
|
||||
<http auto-config="true" request-matcher="path" use-authorization-manager="false">
|
||||
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
|
||||
<http-basic/>
|
||||
</http>
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
http://www.springframework.org/schema/mvc
|
||||
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
<http auto-config="true" request-matcher="mvc">
|
||||
<http auto-config="true" request-matcher="path">
|
||||
<intercept-url pattern="/path" access="denyAll" servlet-path="/spring"/>
|
||||
<http-basic/>
|
||||
</http>
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http>
|
||||
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
|
||||
<http-basic />
|
||||
</http>
|
||||
|
||||
<user-service>
|
||||
<user name="user" password="{noop}password" authorities="ROLE_USER"/>
|
||||
</user-service>
|
||||
|
||||
</b:beans>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -18,6 +18,8 @@ package org.springframework.security.access;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
@ -39,7 +41,7 @@ public interface PermissionEvaluator extends AopInfrastructureBean {
|
||||
* expression system. Not null.
|
||||
* @return true if the permission is granted, false otherwise
|
||||
*/
|
||||
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);
|
||||
boolean hasPermission(Authentication authentication, @Nullable Object targetDomainObject, Object permission);
|
||||
|
||||
/**
|
||||
* Alternative method for evaluating a permission where only the identifier of the
|
||||
|
||||
@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
@ -40,7 +41,7 @@ public class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
||||
* @return false always
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, Object target, Object permission) {
|
||||
public boolean hasPermission(Authentication authentication, @Nullable Object target, Object permission) {
|
||||
this.logger.warn(LogMessage.format("Denying user %s permission '%s' on object %s", authentication.getName(),
|
||||
permission, target));
|
||||
return false;
|
||||
|
||||
@ -38,6 +38,7 @@ import org.springframework.util.function.SingletonSupplier;
|
||||
* @author Luke Taylor
|
||||
* @author Evgeniy Cheban
|
||||
* @author Steve Riesenberg
|
||||
* @author Ngoc Nhan
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SecurityExpressionRoot<T extends @Nullable Object> implements SecurityExpressionOperations {
|
||||
@ -116,7 +117,7 @@ public abstract class SecurityExpressionRoot<T extends @Nullable Object> impleme
|
||||
|
||||
@Override
|
||||
public final boolean hasAuthority(String authority) {
|
||||
return isGranted(this.authorizationManagerFactory.hasAnyAuthority(authority));
|
||||
return isGranted(this.authorizationManagerFactory.hasAuthority(authority));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -208,7 +209,8 @@ public abstract class SecurityExpressionRoot<T extends @Nullable Object> impleme
|
||||
/**
|
||||
* Convenience method to access {@link Authentication#getPrincipal()} from
|
||||
* {@link #getAuthentication()}
|
||||
* @return
|
||||
* @return the {@code Principal} being authenticated or the authenticated principal
|
||||
* after authentication.
|
||||
*/
|
||||
public @Nullable Object getPrincipal() {
|
||||
return getAuthentication().getPrincipal();
|
||||
|
||||
@ -35,6 +35,8 @@ import org.springframework.security.authentication.CredentialsExpiredException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.authentication.ProviderNotFoundException;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent;
|
||||
@ -43,6 +45,7 @@ import org.springframework.security.authentication.event.AuthenticationFailureLo
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent;
|
||||
import org.springframework.security.authentication.ott.OneTimeTokenAuthentication;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
|
||||
@ -60,6 +63,7 @@ class CoreSecurityRuntimeHints implements RuntimeHintsRegistrar {
|
||||
registerExceptionEventsHints(hints);
|
||||
registerExpressionEvaluationHints(hints);
|
||||
registerMethodSecurityHints(hints);
|
||||
registerAdditionalAuthenticationTypes(hints);
|
||||
hints.resources().registerResourceBundle("org.springframework.security.messages");
|
||||
registerDefaultJdbcSchemaFileHint(hints);
|
||||
registerSecurityContextHints(hints);
|
||||
@ -114,4 +118,17 @@ class CoreSecurityRuntimeHints implements RuntimeHintsRegistrar {
|
||||
(builder) -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
}
|
||||
|
||||
private void registerAdditionalAuthenticationTypes(RuntimeHints hints) {
|
||||
// RememberMeAuthenticationToken can be stored in the HTTP session and
|
||||
// deserialized via Jackson (RememberMeAuthenticationTokenMixin exists for both
|
||||
// Jackson 2 and 3), so it needs reflection hints in all native image scenarios.
|
||||
Stream
|
||||
.of(RememberMeAuthenticationToken.class, OneTimeTokenAuthentication.class,
|
||||
UsernamePasswordAuthenticationToken.class)
|
||||
.map(TypeReference::of)
|
||||
.forEach((it) -> hints.reflection()
|
||||
.registerType(it, (builder) -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.ACCESS_DECLARED_FIELDS)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.authentication.dao;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@ -43,6 +44,7 @@ import org.springframework.util.function.SingletonSupplier;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
* @author Andrey Litvitski
|
||||
*/
|
||||
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||
|
||||
@ -131,7 +133,8 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
||||
throw new CompromisedPasswordException("The provided password is compromised, please change your password");
|
||||
}
|
||||
String existingEncodedPassword = user.getPassword();
|
||||
boolean upgradeEncoding = existingEncodedPassword != null && this.userDetailsPasswordService != null
|
||||
boolean upgradeEncoding = existingEncodedPassword != null
|
||||
&& !Objects.equals(this.userDetailsPasswordService, UserDetailsPasswordService.NOOP)
|
||||
&& this.passwordEncoder.get().upgradeEncoding(existingEncodedPassword);
|
||||
if (upgradeEncoding) {
|
||||
String newPassword = this.passwordEncoder.get().encode(presentedPassword);
|
||||
|
||||
@ -69,7 +69,11 @@ public final class AuthoritiesAuthorizationManager implements AuthorizationManag
|
||||
|
||||
private boolean isAuthorized(Authentication authentication, Collection<String> authorities) {
|
||||
for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
|
||||
if (authorities.contains(grantedAuthority.getAuthority())) {
|
||||
String authority = grantedAuthority.getAuthority();
|
||||
if (authority == null) {
|
||||
continue;
|
||||
}
|
||||
if (authorities.contains(authority)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,9 +87,17 @@ public final class RsaKeyConverters {
|
||||
"Key is not in PEM-encoded PKCS#8 format, please check that the header begins with "
|
||||
+ PKCS8_PEM_HEADER);
|
||||
StringBuilder base64Encoded = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
if (RsaKeyConverters.isNotPkcs8Wrapper(line)) {
|
||||
base64Encoded.append(line);
|
||||
if (lines.size() == 1) {
|
||||
base64Encoded.append(lines.get(0)
|
||||
.replace(PKCS8_PEM_HEADER, "")
|
||||
.replace(PKCS8_PEM_FOOTER, "")
|
||||
.replaceAll("\\s+", ""));
|
||||
}
|
||||
else {
|
||||
for (String line : lines) {
|
||||
if (RsaKeyConverters.isNotPkcs8Wrapper(line)) {
|
||||
base64Encoded.append(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] pkcs8 = Base64.getDecoder().decode(base64Encoded.toString());
|
||||
@ -165,9 +173,15 @@ public final class RsaKeyConverters {
|
||||
@Override
|
||||
public @NonNull RSAPublicKey convert(List<String> lines) {
|
||||
StringBuilder base64Encoded = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
if (isNotX509PemWrapper(line)) {
|
||||
base64Encoded.append(line);
|
||||
if (lines.size() == 1) {
|
||||
base64Encoded.append(
|
||||
lines.get(0).replace(X509_PEM_HEADER, "").replace(X509_PEM_FOOTER, "").replaceAll("\\s+", ""));
|
||||
}
|
||||
else {
|
||||
for (String line : lines) {
|
||||
if (isNotX509PemWrapper(line)) {
|
||||
base64Encoded.append(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] x509 = Base64.getDecoder().decode(base64Encoded.toString());
|
||||
@ -196,9 +210,17 @@ public final class RsaKeyConverters {
|
||||
@Override
|
||||
public @NonNull RSAPublicKey convert(List<String> lines) {
|
||||
StringBuilder base64Encoded = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
if (isNotX509CertificateWrapper(line)) {
|
||||
base64Encoded.append(line);
|
||||
if (lines.size() == 1) {
|
||||
base64Encoded.append(lines.get(0)
|
||||
.replace(X509_CERT_HEADER, "")
|
||||
.replace(X509_CERT_FOOTER, "")
|
||||
.replaceAll("\\s+", ""));
|
||||
}
|
||||
else {
|
||||
for (String line : lines) {
|
||||
if (isNotX509CertificateWrapper(line)) {
|
||||
base64Encoded.append(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] x509 = Base64.getDecoder().decode(base64Encoded.toString());
|
||||
|
||||
@ -88,7 +88,6 @@ public final class FactorGrantedAuthority implements GrantedAuthority {
|
||||
|
||||
private final Instant issuedAt;
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private FactorGrantedAuthority(String authority, Instant issuedAt) {
|
||||
Assert.notNull(authority, "authority cannot be null");
|
||||
Assert.notNull(issuedAt, "issuedAt cannot be null");
|
||||
|
||||
@ -21,6 +21,9 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactory;
|
||||
import org.springframework.security.authorization.SingleResultAuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
||||
@ -28,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
@ -174,4 +178,148 @@ public class SecurityExpressionRootTests {
|
||||
assertThat(this.root.isAuthenticated()).isTrue();
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasAuthorityDelegatesToAuthorizationManagerFactoryHasAuthority() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.hasAuthority("CUSTOM_AUTHORITY")).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.hasAuthority("CUSTOM_AUTHORITY")).isFalse();
|
||||
verify(factory).hasAuthority("CUSTOM_AUTHORITY");
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasAnyAuthorityDelegatesToAuthorizationManagerFactoryHasAnyAuthority() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.hasAnyAuthority("CUSTOM_AUTHORITY")).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.hasAnyAuthority("CUSTOM_AUTHORITY")).isFalse();
|
||||
verify(factory).hasAnyAuthority("CUSTOM_AUTHORITY");
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasAllAuthoritiesDelegatesToAuthorizationManagerFactoryHasAllAuthorities() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.hasAllAuthorities("A", "B")).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.hasAllAuthorities("A", "B")).isFalse();
|
||||
verify(factory).hasAllAuthorities("A", "B");
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasRoleDelegatesToAuthorizationManagerFactoryHasRole() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.hasRole("CUSTOM_ROLE")).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.hasRole("CUSTOM_ROLE")).isFalse();
|
||||
verify(factory).hasRole("CUSTOM_ROLE");
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasAnyRoleDelegatesToAuthorizationManagerFactoryHasAnyRole() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.hasAnyRole("A", "B")).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.hasAnyRole("A", "B")).isFalse();
|
||||
verify(factory).hasAnyRole("A", "B");
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasAllRolesDelegatesToAuthorizationManagerFactoryHasAllRoles() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.hasAllRoles("A", "B")).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.hasAllRoles("A", "B")).isFalse();
|
||||
verify(factory).hasAllRoles("A", "B");
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void permitAllDelegatesToAuthorizationManagerFactoryPermitAll() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.permitAll()).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.permitAll()).isFalse();
|
||||
verify(factory).permitAll();
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void denyAllDelegatesToAuthorizationManagerFactoryDenyAll() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.denyAll()).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.denyAll()).isFalse();
|
||||
verify(factory).denyAll();
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void isAnonymousDelegatesToAuthorizationManagerFactoryAnonymous() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.anonymous()).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.isAnonymous()).isFalse();
|
||||
verify(factory).anonymous();
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void isAuthenticatedDelegatesToAuthorizationManagerFactoryAuthenticated() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.authenticated()).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.isAuthenticated()).isFalse();
|
||||
verify(factory).authenticated();
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void isRememberMeDelegatesToAuthorizationManagerFactoryRememberMe() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.rememberMe()).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.isRememberMe()).isFalse();
|
||||
verify(factory).rememberMe();
|
||||
}
|
||||
|
||||
// gh-18486
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void isFullyAuthenticatedDelegatesToAuthorizationManagerFactoryFullyAuthenticated() {
|
||||
AuthorizationManagerFactory<Object> factory = mock(AuthorizationManagerFactory.class);
|
||||
AuthorizationManager<Object> manager = SingleResultAuthorizationManager.denyAll();
|
||||
given(factory.fullyAuthenticated()).willReturn(manager);
|
||||
this.root.setAuthorizationManagerFactory(factory);
|
||||
assertThat(this.root.isFullyAuthenticated()).isFalse();
|
||||
verify(factory).fullyAuthenticated();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ class OneTimeTokenAuthenticationTokenTests {
|
||||
|
||||
// gh-18095
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void shouldBeAbleToDeserializeFromJsonWithDefaultTypingActivated() throws IOException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.registerModules(SecurityJackson2Modules.getModules(getClass().getClassLoader()));
|
||||
|
||||
@ -59,6 +59,7 @@ public class OneTimeTokenReactiveAuthenticationManagerTests {
|
||||
private static final String TOKEN = "token";
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
public void constructorWhenOneTimeTokenServiceNullThenIllegalArgumentException() {
|
||||
ReactiveUserDetailsService userDetailsService = mock(ReactiveUserDetailsService.class);
|
||||
// @formatter:off
|
||||
@ -68,6 +69,7 @@ public class OneTimeTokenReactiveAuthenticationManagerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
public void constructorWhenUserDetailsServiceNullThenIllegalArgumentException() {
|
||||
ReactiveOneTimeTokenService oneTimeTokenService = mock(ReactiveOneTimeTokenService.class);
|
||||
// @formatter:off
|
||||
@ -77,6 +79,7 @@ public class OneTimeTokenReactiveAuthenticationManagerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void authenticateWhenOneTimeTokenAuthenticationTokenIsPresentThenSuccess() {
|
||||
ReactiveOneTimeTokenService oneTimeTokenService = mock(ReactiveOneTimeTokenService.class);
|
||||
given(oneTimeTokenService.consume(ArgumentMatchers.any(OneTimeTokenAuthenticationToken.class)))
|
||||
@ -103,6 +106,7 @@ public class OneTimeTokenReactiveAuthenticationManagerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void authenticateWhenInvalidOneTimeTokenAuthenticationTokenIsPresentThenFail() {
|
||||
ReactiveOneTimeTokenService oneTimeTokenService = mock(ReactiveOneTimeTokenService.class);
|
||||
given(oneTimeTokenService.consume(ArgumentMatchers.any(OneTimeTokenAuthenticationToken.class)))
|
||||
@ -120,6 +124,7 @@ public class OneTimeTokenReactiveAuthenticationManagerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
void authenticateWhenIncorrectTypeOfAuthenticationIsPresentThenFail() {
|
||||
ReactiveOneTimeTokenService oneTimeTokenService = mock(ReactiveOneTimeTokenService.class);
|
||||
given(oneTimeTokenService.consume(ArgumentMatchers.any(OneTimeTokenAuthenticationToken.class)))
|
||||
|
||||
@ -17,7 +17,9 @@
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -30,11 +32,13 @@ import org.springframework.security.core.Authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthoritiesAuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @author Khyojae
|
||||
*/
|
||||
class AuthoritiesAuthorizationManagerTests {
|
||||
|
||||
@ -83,4 +87,20 @@ class AuthoritiesAuthorizationManagerTests {
|
||||
assertThat(manager.authorize(authentication, Collections.singleton("ROLE_USER")).isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
// gh-18543
|
||||
void authorizeWhenAuthorityIsNullThenDoesNotThrowNullPointerException() {
|
||||
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
|
||||
|
||||
Authentication authentication = new TestingAuthenticationToken("user", "password",
|
||||
Collections.singletonList(() -> null));
|
||||
|
||||
Collection<String> authoritiesContainsThrowsNPE = Set.of("ROLE_USER");
|
||||
|
||||
// must be Collection that throws NPE when .contains(null) is invoked
|
||||
// to replicate the issue in gh-18543
|
||||
assertThatNullPointerException().isThrownBy(() -> authoritiesContainsThrowsNPE.contains(null));
|
||||
assertThat(manager.authorize(() -> authentication, authoritiesContainsThrowsNPE).isGranted()).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ public class AuthorityAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void hasAnyRoleWhenNullThenException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> AuthorityAuthorizationManager.hasAnyRole(null))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> AuthorityAuthorizationManager.hasAnyRole((String[]) null))
|
||||
.withMessage("roles cannot be empty");
|
||||
}
|
||||
|
||||
@ -97,7 +97,8 @@ public class AuthorityAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void hasAnyAuthorityWhenNullThenException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> AuthorityAuthorizationManager.hasAnyAuthority(null))
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> AuthorityAuthorizationManager.hasAnyAuthority((String[]) null))
|
||||
.withMessage("authorities cannot be empty");
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user