Skip to content

Commit ad7eead

Browse files
Add Support SingleResultAuthorizationManager
Closes gh-16590 Signed-off-by: Max Batischev <[email protected]>
1 parent 776eb76 commit ad7eead

File tree

9 files changed

+97
-38
lines changed

9 files changed

+97
-38
lines changed

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

Lines changed: 4 additions & 8 deletions
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.PERMIT_ALL());
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.DENY_ALL());
302298
}
303299

304300
/**

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

Lines changed: 3 additions & 2 deletions
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.PERMIT_ALL());
6768
}
6869
}
6970
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
23+
/**
24+
* An {@link AuthorizationManager} which creates permit-all and deny-all
25+
* {@link AuthorizationManager} instances.
26+
*
27+
* @author Max Batischev
28+
* @since 6.5
29+
*/
30+
public final class SingleResultAuthorizationManager<C> implements AuthorizationManager<C> {
31+
32+
private static final AuthorizationDecision DENY = new AuthorizationDecision(false);
33+
34+
private static final AuthorizationDecision PERMIT = new AuthorizationDecision(true);
35+
36+
/**
37+
* Creates permit-all {@link AuthorizationManager} instance.
38+
* @param <C>
39+
* @return permit-all {@link AuthorizationManager} instance
40+
*/
41+
public static <C> AuthorizationManager<C> PERMIT_ALL() {
42+
return (a, o) -> PERMIT;
43+
}
44+
45+
/**
46+
* Creates deny-all {@link AuthorizationManager} instance.
47+
* @param <C>
48+
* @return deny-all {@link AuthorizationManager} instance
49+
*/
50+
public static <C> AuthorizationManager<C> DENY_ALL() {
51+
return (a, o) -> DENY;
52+
}
53+
54+
private SingleResultAuthorizationManager() {
55+
}
56+
57+
@Override
58+
public AuthorizationDecision check(Supplier<Authentication> authentication, C object) {
59+
throw new UnsupportedOperationException("Not supported");
60+
}
61+
62+
}

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

Lines changed: 4 additions & 3 deletions
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.DENY_ALL();
110111
}
111112
if (annotation instanceof PermitAll) {
112-
return (a, o) -> new AuthorizationDecision(true);
113+
return SingleResultAuthorizationManager.PERMIT_ALL();
113114
}
114115
if (annotation instanceof RolesAllowed rolesAllowed) {
115116
return (AuthorizationManagerCheckAdapter<MethodInvocation>) (a,

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

Lines changed: 3 additions & 7 deletions
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.PERMIT_ALL().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.DENY_ALL().verify(() -> authentication, object))
6359
.withMessage("Access Denied");
6460
}
6561

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

Lines changed: 6 additions & 6 deletions
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.DENY_ALL(),
33+
SingleResultAuthorizationManager.PERMIT_ALL());
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.PERMIT_ALL(),
122+
SingleResultAuthorizationManager.PERMIT_ALL());
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.PERMIT_ALL(), SingleResultAuthorizationManager.DENY_ALL());
162162
AuthorizationDecision decision = composed.check(null, null);
163163
assertThat(decision).isNotNull();
164164
assertThat(decision.isGranted()).isFalse();

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

Lines changed: 4 additions & 3 deletions
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.PERMIT_ALL());
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.DENY_ALL());
331332
}
332333

333334
/**

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

Lines changed: 4 additions & 3 deletions
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.PERMIT_ALL());
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.DENY_ALL());
213214
}
214215

215216
/**

web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java

Lines changed: 7 additions & 6 deletions
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.
@@ -26,6 +26,7 @@
2626
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
2727
import org.springframework.security.authorization.AuthorityAuthorizationManager;
2828
import org.springframework.security.authorization.AuthorizationDecision;
29+
import org.springframework.security.authorization.SingleResultAuthorizationManager;
2930
import org.springframework.security.core.Authentication;
3031
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
3132
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -55,7 +56,7 @@ public void buildWhenMappingsEmptyThenException() {
5556
public void addWhenMatcherNullThenException() {
5657
assertThatIllegalArgumentException()
5758
.isThrownBy(() -> RequestMatcherDelegatingAuthorizationManager.builder()
58-
.add(null, (a, o) -> new AuthorizationDecision(true))
59+
.add(null, SingleResultAuthorizationManager.PERMIT_ALL())
5960
.build())
6061
.withMessage("matcher cannot be null");
6162
}
@@ -72,8 +73,8 @@ public void addWhenManagerNullThenException() {
7273
@Test
7374
public void checkWhenMultipleMappingsConfiguredThenDelegatesMatchingManager() {
7475
RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder()
75-
.add(new MvcRequestMatcher(null, "/grant"), (a, o) -> new AuthorizationDecision(true))
76-
.add(new MvcRequestMatcher(null, "/deny"), (a, o) -> new AuthorizationDecision(false))
76+
.add(new MvcRequestMatcher(null, "/grant"), SingleResultAuthorizationManager.PERMIT_ALL())
77+
.add(new MvcRequestMatcher(null, "/deny"), SingleResultAuthorizationManager.DENY_ALL())
7778
.build();
7879

7980
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
@@ -97,11 +98,11 @@ public void checkWhenMultipleMappingsConfiguredWithConsumerThenDelegatesMatching
9798
RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder()
9899
.mappings((m) -> {
99100
m.add(new RequestMatcherEntry<>(new MvcRequestMatcher(null, "/grant"),
100-
(a, o) -> new AuthorizationDecision(true)));
101+
SingleResultAuthorizationManager.PERMIT_ALL()));
101102
m.add(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE,
102103
AuthorityAuthorizationManager.hasRole("ADMIN")));
103104
m.add(new RequestMatcherEntry<>(new MvcRequestMatcher(null, "/afterAny"),
104-
(a, o) -> new AuthorizationDecision(true)));
105+
SingleResultAuthorizationManager.PERMIT_ALL()));
105106
})
106107
.build();
107108

0 commit comments

Comments
 (0)