diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java index 79a5d83af5e..d4ce44049ac 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -33,6 +33,7 @@ import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManagers; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.authorization.SpringAuthorizationEventPublisher; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; @@ -57,11 +58,6 @@ public final class AuthorizeHttpRequestsConfigurer> extends AbstractHttpConfigurer, H> { - static final AuthorizationDecision AUTHORIZATION_DECISION = new AuthorizationDecision(true); - - static final AuthorizationManager PERMIT_ALL_AUTHORIZATION_MANAGER = (a, - o) -> AUTHORIZATION_DECISION; - private final AuthorizationManagerRequestMatcherRegistry registry; private final AuthorizationEventPublisher publisher; @@ -289,7 +285,7 @@ public AuthorizedUrl not() { * customizations */ public AuthorizationManagerRequestMatcherRegistry permitAll() { - return access(PERMIT_ALL_AUTHORIZATION_MANAGER); + return access(SingleResultAuthorizationManager.PERMIT_ALL()); } /** @@ -298,7 +294,7 @@ public AuthorizationManagerRequestMatcherRegistry permitAll() { * customizations */ public AuthorizationManagerRequestMatcherRegistry denyAll() { - return access((a, o) -> new AuthorizationDecision(false)); + return access(SingleResultAuthorizationManager.DENY_ALL()); } /** diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java index 5c8028567a3..936bac04239 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 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. @@ -19,6 +19,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.access.SecurityConfig; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry.UrlMapping; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -63,7 +64,7 @@ static void permitAll(HttpSecurityBuilder> http SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll))); } else { - httpConfigurer.addFirst(matcher, AuthorizeHttpRequestsConfigurer.PERMIT_ALL_AUTHORIZATION_MANAGER); + httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.PERMIT_ALL()); } } } diff --git a/core/src/main/java/org/springframework/security/authorization/SingleResultAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/SingleResultAuthorizationManager.java new file mode 100644 index 00000000000..f8b8048e648 --- /dev/null +++ b/core/src/main/java/org/springframework/security/authorization/SingleResultAuthorizationManager.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2025 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.authorization; + +import java.util.function.Supplier; + +import org.springframework.security.core.Authentication; + +/** + * An {@link AuthorizationManager} which creates permit-all and deny-all + * {@link AuthorizationManager} instances. + * + * @author Max Batischev + * @since 6.5 + */ +public final class SingleResultAuthorizationManager implements AuthorizationManager { + + private static final AuthorizationDecision DENY = new AuthorizationDecision(false); + + private static final AuthorizationDecision PERMIT = new AuthorizationDecision(true); + + /** + * Creates permit-all {@link AuthorizationManager} instance. + * @param + * @return permit-all {@link AuthorizationManager} instance + */ + public static AuthorizationManager PERMIT_ALL() { + return (a, o) -> PERMIT; + } + + /** + * Creates deny-all {@link AuthorizationManager} instance. + * @param + * @return deny-all {@link AuthorizationManager} instance + */ + public static AuthorizationManager DENY_ALL() { + return (a, o) -> DENY; + } + + private SingleResultAuthorizationManager() { + } + + @Override + public AuthorizationDecision check(Supplier authentication, C object) { + throw new UnsupportedOperationException("Not supported"); + } + +} diff --git a/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java index 30c3977db5e..eb596ed08e7 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -34,6 +34,7 @@ import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationResult; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.SecurityAnnotationScanner; import org.springframework.security.core.annotation.SecurityAnnotationScanners; @@ -106,10 +107,10 @@ private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthoriza AuthorizationManager resolveManager(Method method, Class targetClass) { Annotation annotation = findJsr250Annotation(method, targetClass); if (annotation instanceof DenyAll) { - return (a, o) -> new AuthorizationDecision(false); + return SingleResultAuthorizationManager.DENY_ALL(); } if (annotation instanceof PermitAll) { - return (a, o) -> new AuthorizationDecision(true); + return SingleResultAuthorizationManager.PERMIT_ALL(); } if (annotation instanceof RolesAllowed rolesAllowed) { return (AuthorizationManagerCheckAdapter) (a, diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagerTests.java index bf2e8c36265..c7669197ef4 100644 --- a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 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. @@ -33,12 +33,10 @@ public class AuthorizationManagerTests { @Test public void verifyWhenCheckReturnedGrantedDecisionThenPasses() { - AuthorizationManager manager = (a, o) -> new AuthorizationDecision(true); - Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_1", "ROLE_2"); Object object = new Object(); - manager.verify(() -> authentication, object); + SingleResultAuthorizationManager.PERMIT_ALL().verify(() -> authentication, object); } @Test @@ -53,13 +51,11 @@ public void verifyWhenCheckReturnedNullThenPasses() { @Test public void verifyWhenCheckReturnedDeniedDecisionThenAccessDeniedException() { - AuthorizationManager manager = (a, o) -> new AuthorizationDecision(false); - Authentication authentication = new TestingAuthenticationToken("user", "password", "ROLE_1", "ROLE_2"); Object object = new Object(); assertThatExceptionOfType(AccessDeniedException.class) - .isThrownBy(() -> manager.verify(() -> authentication, object)) + .isThrownBy(() -> SingleResultAuthorizationManager.DENY_ALL().verify(() -> authentication, object)) .withMessage("Access Denied"); } diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java index ba32fb63bbd..979ccf824ee 100644 --- a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java +++ b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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. @@ -29,8 +29,8 @@ class AuthorizationManagersTests { @Test void checkAnyOfWhenOneGrantedThenGrantedDecision() { - AuthorizationManager composed = AuthorizationManagers.anyOf((a, o) -> new AuthorizationDecision(false), - (a, o) -> new AuthorizationDecision(true)); + AuthorizationManager composed = AuthorizationManagers.anyOf(SingleResultAuthorizationManager.DENY_ALL(), + SingleResultAuthorizationManager.PERMIT_ALL()); AuthorizationDecision decision = composed.check(null, null); assertThat(decision).isNotNull(); assertThat(decision.isGranted()).isTrue(); @@ -118,8 +118,8 @@ void checkAnyOfWhenAllAbstainDefaultDecisionIsAbstainAndAllManagersAbstainThenAb @Test void checkAllOfWhenAllGrantedThenGrantedDecision() { - AuthorizationManager composed = AuthorizationManagers.allOf((a, o) -> new AuthorizationDecision(true), - (a, o) -> new AuthorizationDecision(true)); + AuthorizationManager composed = AuthorizationManagers.allOf(SingleResultAuthorizationManager.PERMIT_ALL(), + SingleResultAuthorizationManager.PERMIT_ALL()); AuthorizationDecision decision = composed.check(null, null); assertThat(decision).isNotNull(); assertThat(decision.isGranted()).isTrue(); @@ -158,7 +158,7 @@ void checkAllOfWhenOneDeniedThenDeniedDecision() { void checkAllOfWithAllAbstainDefaultDecisionWhenOneDeniedThenDeniedDecision() { AuthorizationDecision allAbstainDefaultDecision = new AuthorizationDecision(true); AuthorizationManager composed = AuthorizationManagers.allOf(allAbstainDefaultDecision, - (a, o) -> new AuthorizationDecision(true), (a, o) -> new AuthorizationDecision(false)); + SingleResultAuthorizationManager.PERMIT_ALL(), SingleResultAuthorizationManager.DENY_ALL()); AuthorizationDecision decision = composed.check(null, null); assertThat(decision).isNotNull(); assertThat(decision.isGranted()).isFalse(); diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java index d735fc5a422..e71aaaeb285 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 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. @@ -31,6 +31,7 @@ import org.springframework.security.authorization.AuthorityAuthorizationManager; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.messaging.util.matcher.MessageMatcher; import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher; @@ -319,7 +320,7 @@ public Builder hasAnyAuthority(String... authorities) { * @return the {@link Builder} for further customization */ public Builder permitAll() { - return access((authentication, context) -> new AuthorizationDecision(true)); + return access(SingleResultAuthorizationManager.PERMIT_ALL()); } /** @@ -327,7 +328,7 @@ public Builder permitAll() { * @return the {@link Builder} for further customization */ public Builder denyAll() { - return access((authorization, context) -> new AuthorizationDecision(false)); + return access(SingleResultAuthorizationManager.DENY_ALL()); } /** diff --git a/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java b/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java index 1c26f9b0a4d..b09708a9aca 100644 --- a/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java +++ b/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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. @@ -30,6 +30,7 @@ import org.springframework.security.authorization.AuthorityAuthorizationManager; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.web.util.UrlUtils; import org.springframework.security.web.util.matcher.AnyRequestMatcher; @@ -201,7 +202,7 @@ private AuthorizedUrl(List matchers) { * @return the {@link Builder} for further customizations */ public Builder permitAll() { - return access((a, o) -> new AuthorizationDecision(true)); + return access(SingleResultAuthorizationManager.PERMIT_ALL()); } /** @@ -209,7 +210,7 @@ public Builder permitAll() { * @return the {@link Builder} for further customizations */ public Builder denyAll() { - return access((a, o) -> new AuthorizationDecision(false)); + return access(SingleResultAuthorizationManager.DENY_ALL()); } /** diff --git a/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java b/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java index aa969ce2bb8..bfce68021b2 100644 --- a/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java +++ b/web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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. @@ -26,6 +26,7 @@ import org.springframework.security.authorization.AuthenticatedAuthorizationManager; import org.springframework.security.authorization.AuthorityAuthorizationManager; import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @@ -55,7 +56,7 @@ public void buildWhenMappingsEmptyThenException() { public void addWhenMatcherNullThenException() { assertThatIllegalArgumentException() .isThrownBy(() -> RequestMatcherDelegatingAuthorizationManager.builder() - .add(null, (a, o) -> new AuthorizationDecision(true)) + .add(null, SingleResultAuthorizationManager.PERMIT_ALL()) .build()) .withMessage("matcher cannot be null"); } @@ -72,8 +73,8 @@ public void addWhenManagerNullThenException() { @Test public void checkWhenMultipleMappingsConfiguredThenDelegatesMatchingManager() { RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder() - .add(new MvcRequestMatcher(null, "/grant"), (a, o) -> new AuthorizationDecision(true)) - .add(new MvcRequestMatcher(null, "/deny"), (a, o) -> new AuthorizationDecision(false)) + .add(new MvcRequestMatcher(null, "/grant"), SingleResultAuthorizationManager.PERMIT_ALL()) + .add(new MvcRequestMatcher(null, "/deny"), SingleResultAuthorizationManager.DENY_ALL()) .build(); Supplier authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER"); @@ -97,11 +98,11 @@ public void checkWhenMultipleMappingsConfiguredWithConsumerThenDelegatesMatching RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder() .mappings((m) -> { m.add(new RequestMatcherEntry<>(new MvcRequestMatcher(null, "/grant"), - (a, o) -> new AuthorizationDecision(true))); + SingleResultAuthorizationManager.PERMIT_ALL())); m.add(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE, AuthorityAuthorizationManager.hasRole("ADMIN"))); m.add(new RequestMatcherEntry<>(new MvcRequestMatcher(null, "/afterAny"), - (a, o) -> new AuthorizationDecision(true))); + SingleResultAuthorizationManager.PERMIT_ALL())); }) .build();