Skip to content

Add SingleResultAuthorizationManager #16612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
Expand All @@ -57,11 +58,6 @@
public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<AuthorizeHttpRequestsConfigurer<H>, H> {

static final AuthorizationDecision AUTHORIZATION_DECISION = new AuthorizationDecision(true);

static final AuthorizationManager<RequestAuthorizationContext> PERMIT_ALL_AUTHORIZATION_MANAGER = (a,
o) -> AUTHORIZATION_DECISION;

private final AuthorizationManagerRequestMatcherRegistry registry;

private final AuthorizationEventPublisher publisher;
Expand Down Expand Up @@ -289,7 +285,7 @@ public AuthorizedUrl not() {
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry permitAll() {
return access(PERMIT_ALL_AUTHORIZATION_MANAGER);
return access(SingleResultAuthorizationManager.permitAll());
}

/**
Expand All @@ -298,7 +294,7 @@ public AuthorizationManagerRequestMatcherRegistry permitAll() {
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry denyAll() {
return access((a, o) -> new AuthorizationDecision(false));
return access(SingleResultAuthorizationManager.denyAll());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -63,7 +64,7 @@ static void permitAll(HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
}
else {
httpConfigurer.addFirst(matcher, AuthorizeHttpRequestsConfigurer.PERMIT_ALL_AUTHORIZATION_MANAGER);
httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.permitAll());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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;
import org.springframework.util.Assert;

/**
* An {@link AuthorizationManager} which creates permit-all and deny-all
* {@link AuthorizationManager} instances.
*
* @author Max Batischev
* @since 6.5
*/
public final class SingleResultAuthorizationManager<C> implements AuthorizationManager<C> {

private static final SingleResultAuthorizationManager<?> DENY_MANAGER = new SingleResultAuthorizationManager<>(
new AuthorizationDecision(false));

private static final SingleResultAuthorizationManager<?> PERMIT_MANAGER = new SingleResultAuthorizationManager<>(
new AuthorizationDecision(true));

private final AuthorizationResult result;

public SingleResultAuthorizationManager(AuthorizationResult result) {
Assert.notNull(result, "result cannot be null");
this.result = result;
}

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, C object) {
if (!(this.result instanceof AuthorizationDecision)) {
throw new IllegalArgumentException("result should be AuthorizationDecision");
}
return (AuthorizationDecision) this.result;
}

@Override
public AuthorizationResult authorize(Supplier<Authentication> authentication, C object) {
return this.result;
}

@SuppressWarnings("unchecked")
public static <C> SingleResultAuthorizationManager<C> denyAll() {
return (SingleResultAuthorizationManager<C>) DENY_MANAGER;
}

@SuppressWarnings("unchecked")
public static <C> SingleResultAuthorizationManager<C> permitAll() {
return (SingleResultAuthorizationManager<C>) PERMIT_MANAGER;
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -106,10 +107,10 @@ private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthoriza
AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
Annotation annotation = findJsr250Annotation(method, targetClass);
if (annotation instanceof DenyAll) {
return (a, o) -> new AuthorizationDecision(false);
return SingleResultAuthorizationManager.denyAll();
}
if (annotation instanceof PermitAll) {
return (a, o) -> new AuthorizationDecision(true);
return SingleResultAuthorizationManager.permitAll();
}
if (annotation instanceof RolesAllowed rolesAllowed) {
return (AuthorizationManagerCheckAdapter<MethodInvocation>) (a,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -33,12 +33,10 @@ public class AuthorizationManagerTests {

@Test
public void verifyWhenCheckReturnedGrantedDecisionThenPasses() {
AuthorizationManager<Object> 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.permitAll().verify(() -> authentication, object);
}

@Test
Expand All @@ -53,13 +51,11 @@ public void verifyWhenCheckReturnedNullThenPasses() {

@Test
public void verifyWhenCheckReturnedDeniedDecisionThenAccessDeniedException() {
AuthorizationManager<Object> 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.denyAll().verify(() -> authentication, object))
.withMessage("Access Denied");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.permitAll(),
SingleResultAuthorizationManager.permitAll());
AuthorizationDecision decision = composed.check(null, null);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
Expand Down Expand Up @@ -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.permitAll(),
SingleResultAuthorizationManager.permitAll());
AuthorizationDecision decision = composed.check(null, null);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isTrue();
Expand Down Expand Up @@ -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.permitAll(), SingleResultAuthorizationManager.denyAll());
AuthorizationDecision decision = composed.check(null, null);
assertThat(decision).isNotNull();
assertThat(decision.isGranted()).isFalse();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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 org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

/**
* Tests for {@link SingleResultAuthorizationManager}.
*
* @author Max Batischev
*/
public class SingleResultAuthorizationManagerTests {

private SingleResultAuthorizationManager<?> manager;

@Test
void authorizeWhenManagerWithGrantedAuthorizationResultIsCreatedThenAuthorizes() {
this.manager = new SingleResultAuthorizationManager<>(new AuthorizationDecision(true));

AuthorizationResult result = this.manager.authorize(null, null);

assertThat(result.isGranted()).isTrue();
}

@Test
void checkWhenManagerWithGrantedDecisionIsCreatedThenAuthorizes() {
this.manager = new SingleResultAuthorizationManager<>(new AuthorizationDecision(true));

AuthorizationResult result = this.manager.check(null, null);

assertThat(result.isGranted()).isTrue();
}

@Test
void checkWhenManagerWithGrantedCustomAuthorizationResultIsCreatedThenFails() {
this.manager = new SingleResultAuthorizationManager<>((AuthorizationResult) () -> true);

assertThatIllegalArgumentException().isThrownBy(() -> this.manager.check(null, null));
}

@Test
void authorizeWhenPermitManagerUsesThenAuthorize() {
AuthorizationResult result = SingleResultAuthorizationManager.permitAll().authorize(null, null);

assertThat(result.isGranted()).isTrue();
}

@Test
void authorizeWhenDenyManagerUsesThenDeny() {
AuthorizationResult result = SingleResultAuthorizationManager.denyAll().authorize(null, null);

assertThat(result.isGranted()).isFalse();
}

@Test
void constructWhenNullResultIsPresentThenFails() {
assertThatIllegalArgumentException().isThrownBy(() -> new SingleResultAuthorizationManager<>(null));
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -319,15 +320,15 @@ 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.permitAll());
}

/**
* Specify that Messages are not allowed by anyone.
* @return the {@link Builder} for further customization
*/
public Builder denyAll() {
return access((authorization, context) -> new AuthorizationDecision(false));
return access(SingleResultAuthorizationManager.denyAll());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -201,15 +202,15 @@ private AuthorizedUrl(List<RequestMatcher> matchers) {
* @return the {@link Builder} for further customizations
*/
public Builder permitAll() {
return access((a, o) -> new AuthorizationDecision(true));
return access(SingleResultAuthorizationManager.permitAll());
}

/**
* Specify that URLs are not allowed by anyone.
* @return the {@link Builder} for further customizations
*/
public Builder denyAll() {
return access((a, o) -> new AuthorizationDecision(false));
return access(SingleResultAuthorizationManager.denyAll());
}

/**
Expand Down
Loading