Skip to content

Commit 58a665e

Browse files
franticticktickjzheaux
authored andcommitted
Add Support SingleResultAuthorizationManager
Closes gh-16590 Signed-off-by: Max Batischev <mblancer@mail.ru>
1 parent 29f1ea5 commit 58a665e

File tree

10 files changed

+181
-38
lines changed

10 files changed

+181
-38
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
3333
import org.springframework.security.authorization.AuthorizationEventPublisher;
3434
import org.springframework.security.authorization.AuthorizationManager;
3535
import org.springframework.security.authorization.AuthorizationManagers;
36+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
3637
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
3738
import org.springframework.security.config.ObjectPostProcessor;
3839
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
@@ -57,11 +58,6 @@
5758
public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
5859
extends AbstractHttpConfigurer<AuthorizeHttpRequestsConfigurer<H>, H> {
5960

60-
static final AuthorizationDecision AUTHORIZATION_DECISION = new AuthorizationDecision(true);
61-
62-
static final AuthorizationManager<RequestAuthorizationContext> PERMIT_ALL_AUTHORIZATION_MANAGER = (a,
63-
o) -> AUTHORIZATION_DECISION;
64-
6561
private final AuthorizationManagerRequestMatcherRegistry registry;
6662

6763
private final AuthorizationEventPublisher publisher;
@@ -289,7 +285,7 @@ public AuthorizedUrl not() {
289285
* customizations
290286
*/
291287
public AuthorizationManagerRequestMatcherRegistry permitAll() {
292-
return access(PERMIT_ALL_AUTHORIZATION_MANAGER);
288+
return access(SingleResultAuthorizationManager.permitAll());
293289
}
294290

295291
/**
@@ -298,7 +294,7 @@ public AuthorizationManagerRequestMatcherRegistry permitAll() {
298294
* customizations
299295
*/
300296
public AuthorizationManagerRequestMatcherRegistry denyAll() {
301-
return access((a, o) -> new AuthorizationDecision(false));
297+
return access(SingleResultAuthorizationManager.denyAll());
302298
}
303299

304300
/**

config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import jakarta.servlet.http.HttpServletRequest;
2020

2121
import org.springframework.security.access.SecurityConfig;
22+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
2223
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
2324
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry.UrlMapping;
2425
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -63,7 +64,7 @@ static void permitAll(HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http
6364
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
6465
}
6566
else {
66-
httpConfigurer.addFirst(matcher, AuthorizeHttpRequestsConfigurer.PERMIT_ALL_AUTHORIZATION_MANAGER);
67+
httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.permitAll());
6768
}
6869
}
6970
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2002-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authorization;
18+
19+
import java.util.function.Supplier;
20+
21+
import org.springframework.security.core.Authentication;
22+
import org.springframework.util.Assert;
23+
24+
/**
25+
* An {@link AuthorizationManager} which creates permit-all and deny-all
26+
* {@link AuthorizationManager} instances.
27+
*
28+
* @author Max Batischev
29+
* @since 6.5
30+
*/
31+
public final class SingleResultAuthorizationManager<C> implements AuthorizationManager<C> {
32+
33+
private static final SingleResultAuthorizationManager<?> DENY_MANAGER = new SingleResultAuthorizationManager<>(
34+
new AuthorizationDecision(false));
35+
36+
private static final SingleResultAuthorizationManager<?> PERMIT_MANAGER = new SingleResultAuthorizationManager<>(
37+
new AuthorizationDecision(true));
38+
39+
private final AuthorizationResult result;
40+
41+
public SingleResultAuthorizationManager(AuthorizationResult result) {
42+
Assert.notNull(result, "result cannot be null");
43+
this.result = result;
44+
}
45+
46+
@Override
47+
public AuthorizationDecision check(Supplier<Authentication> authentication, C object) {
48+
if (!(this.result instanceof AuthorizationDecision)) {
49+
throw new IllegalArgumentException("result should be AuthorizationDecision");
50+
}
51+
return (AuthorizationDecision) this.result;
52+
}
53+
54+
@Override
55+
public AuthorizationResult authorize(Supplier<Authentication> authentication, C object) {
56+
return this.result;
57+
}
58+
59+
@SuppressWarnings("unchecked")
60+
public static <C> SingleResultAuthorizationManager<C> denyAll() {
61+
return (SingleResultAuthorizationManager<C>) DENY_MANAGER;
62+
}
63+
64+
@SuppressWarnings("unchecked")
65+
public static <C> SingleResultAuthorizationManager<C> permitAll() {
66+
return (SingleResultAuthorizationManager<C>) PERMIT_MANAGER;
67+
}
68+
69+
}

core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import org.springframework.security.authorization.AuthorizationDecision;
3535
import org.springframework.security.authorization.AuthorizationManager;
3636
import org.springframework.security.authorization.AuthorizationResult;
37+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
3738
import org.springframework.security.core.Authentication;
3839
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
3940
import org.springframework.security.core.annotation.SecurityAnnotationScanners;
@@ -106,10 +107,10 @@ private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthoriza
106107
AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
107108
Annotation annotation = findJsr250Annotation(method, targetClass);
108109
if (annotation instanceof DenyAll) {
109-
return (a, o) -> new AuthorizationDecision(false);
110+
return SingleResultAuthorizationManager.denyAll();
110111
}
111112
if (annotation instanceof PermitAll) {
112-
return (a, o) -> new AuthorizationDecision(true);
113+
return SingleResultAuthorizationManager.permitAll();
113114
}
114115
if (annotation instanceof RolesAllowed rolesAllowed) {
115116
return (AuthorizationManagerCheckAdapter<MethodInvocation>) (a,

core/src/test/java/org/springframework/security/authorization/AuthorizationManagerTests.java

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,12 +33,10 @@ public class AuthorizationManagerTests {
3333

3434
@Test
3535
public void verifyWhenCheckReturnedGrantedDecisionThenPasses() {
36-
AuthorizationManager<Object> manager = (a, o) -> new AuthorizationDecision(true);
37-
3836
Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_1", "ROLE_2");
3937
Object object = new Object();
4038

41-
manager.verify(() -> authentication, object);
39+
SingleResultAuthorizationManager.permitAll().verify(() -> authentication, object);
4240
}
4341

4442
@Test
@@ -53,13 +51,11 @@ public void verifyWhenCheckReturnedNullThenPasses() {
5351

5452
@Test
5553
public void verifyWhenCheckReturnedDeniedDecisionThenAccessDeniedException() {
56-
AuthorizationManager<Object> manager = (a, o) -> new AuthorizationDecision(false);
57-
5854
Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_1", "ROLE_2");
5955
Object object = new Object();
6056

6157
assertThatExceptionOfType(AccessDeniedException.class)
62-
.isThrownBy(() -> manager.verify(() -> authentication, object))
58+
.isThrownBy(() -> SingleResultAuthorizationManager.denyAll().verify(() -> authentication, object))
6359
.withMessage("Access Denied");
6460
}
6561

core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,8 +29,8 @@ class AuthorizationManagersTests {
2929

3030
@Test
3131
void checkAnyOfWhenOneGrantedThenGrantedDecision() {
32-
AuthorizationManager<?> composed = AuthorizationManagers.anyOf((a, o) -> new AuthorizationDecision(false),
33-
(a, o) -> new AuthorizationDecision(true));
32+
AuthorizationManager<?> composed = AuthorizationManagers.anyOf(SingleResultAuthorizationManager.permitAll(),
33+
SingleResultAuthorizationManager.permitAll());
3434
AuthorizationDecision decision = composed.check(null, null);
3535
assertThat(decision).isNotNull();
3636
assertThat(decision.isGranted()).isTrue();
@@ -118,8 +118,8 @@ void checkAnyOfWhenAllAbstainDefaultDecisionIsAbstainAndAllManagersAbstainThenAb
118118

119119
@Test
120120
void checkAllOfWhenAllGrantedThenGrantedDecision() {
121-
AuthorizationManager<?> composed = AuthorizationManagers.allOf((a, o) -> new AuthorizationDecision(true),
122-
(a, o) -> new AuthorizationDecision(true));
121+
AuthorizationManager<?> composed = AuthorizationManagers.allOf(SingleResultAuthorizationManager.permitAll(),
122+
SingleResultAuthorizationManager.permitAll());
123123
AuthorizationDecision decision = composed.check(null, null);
124124
assertThat(decision).isNotNull();
125125
assertThat(decision.isGranted()).isTrue();
@@ -158,7 +158,7 @@ void checkAllOfWhenOneDeniedThenDeniedDecision() {
158158
void checkAllOfWithAllAbstainDefaultDecisionWhenOneDeniedThenDeniedDecision() {
159159
AuthorizationDecision allAbstainDefaultDecision = new AuthorizationDecision(true);
160160
AuthorizationManager<?> composed = AuthorizationManagers.allOf(allAbstainDefaultDecision,
161-
(a, o) -> new AuthorizationDecision(true), (a, o) -> new AuthorizationDecision(false));
161+
SingleResultAuthorizationManager.permitAll(), SingleResultAuthorizationManager.denyAll());
162162
AuthorizationDecision decision = composed.check(null, null);
163163
assertThat(decision).isNotNull();
164164
assertThat(decision.isGranted()).isFalse();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2002-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authorization;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
23+
24+
/**
25+
* Tests for {@link SingleResultAuthorizationManager}.
26+
*
27+
* @author Max Batischev
28+
*/
29+
public class SingleResultAuthorizationManagerTests {
30+
31+
private SingleResultAuthorizationManager<?> manager;
32+
33+
@Test
34+
void authorizeWhenManagerWithGrantedAuthorizationResultIsCreatedThenAuthorizes() {
35+
this.manager = new SingleResultAuthorizationManager<>(new AuthorizationDecision(true));
36+
37+
AuthorizationResult result = this.manager.authorize(null, null);
38+
39+
assertThat(result.isGranted()).isTrue();
40+
}
41+
42+
@Test
43+
void checkWhenManagerWithGrantedDecisionIsCreatedThenAuthorizes() {
44+
this.manager = new SingleResultAuthorizationManager<>(new AuthorizationDecision(true));
45+
46+
AuthorizationResult result = this.manager.check(null, null);
47+
48+
assertThat(result.isGranted()).isTrue();
49+
}
50+
51+
@Test
52+
void checkWhenManagerWithGrantedCustomAuthorizationResultIsCreatedThenFails() {
53+
this.manager = new SingleResultAuthorizationManager<>((AuthorizationResult) () -> true);
54+
55+
assertThatIllegalArgumentException().isThrownBy(() -> this.manager.check(null, null));
56+
}
57+
58+
@Test
59+
void authorizeWhenPermitManagerUsesThenAuthorize() {
60+
AuthorizationResult result = SingleResultAuthorizationManager.permitAll().authorize(null, null);
61+
62+
assertThat(result.isGranted()).isTrue();
63+
}
64+
65+
@Test
66+
void authorizeWhenDenyManagerUsesThenDeny() {
67+
AuthorizationResult result = SingleResultAuthorizationManager.denyAll().authorize(null, null);
68+
69+
assertThat(result.isGranted()).isFalse();
70+
}
71+
72+
@Test
73+
void constructWhenNullResultIsPresentThenFails() {
74+
assertThatIllegalArgumentException().isThrownBy(() -> new SingleResultAuthorizationManager<>(null));
75+
}
76+
77+
}

messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
import org.springframework.security.authorization.AuthorityAuthorizationManager;
3232
import org.springframework.security.authorization.AuthorizationDecision;
3333
import org.springframework.security.authorization.AuthorizationManager;
34+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
3435
import org.springframework.security.core.Authentication;
3536
import org.springframework.security.messaging.util.matcher.MessageMatcher;
3637
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
@@ -319,15 +320,15 @@ public Builder hasAnyAuthority(String... authorities) {
319320
* @return the {@link Builder} for further customization
320321
*/
321322
public Builder permitAll() {
322-
return access((authentication, context) -> new AuthorizationDecision(true));
323+
return access(SingleResultAuthorizationManager.permitAll());
323324
}
324325

325326
/**
326327
* Specify that Messages are not allowed by anyone.
327328
* @return the {@link Builder} for further customization
328329
*/
329330
public Builder denyAll() {
330-
return access((authorization, context) -> new AuthorizationDecision(false));
331+
return access(SingleResultAuthorizationManager.denyAll());
331332
}
332333

333334
/**

web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
import org.springframework.security.authorization.AuthorityAuthorizationManager;
3131
import org.springframework.security.authorization.AuthorizationDecision;
3232
import org.springframework.security.authorization.AuthorizationManager;
33+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
3334
import org.springframework.security.core.Authentication;
3435
import org.springframework.security.web.util.UrlUtils;
3536
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
@@ -201,15 +202,15 @@ private AuthorizedUrl(List<RequestMatcher> matchers) {
201202
* @return the {@link Builder} for further customizations
202203
*/
203204
public Builder permitAll() {
204-
return access((a, o) -> new AuthorizationDecision(true));
205+
return access(SingleResultAuthorizationManager.permitAll());
205206
}
206207

207208
/**
208209
* Specify that URLs are not allowed by anyone.
209210
* @return the {@link Builder} for further customizations
210211
*/
211212
public Builder denyAll() {
212-
return access((a, o) -> new AuthorizationDecision(false));
213+
return access(SingleResultAuthorizationManager.denyAll());
213214
}
214215

215216
/**

0 commit comments

Comments
 (0)