Skip to content

Commit

Permalink
Add support AuthorizationResult for AuthorizationManager
Browse files Browse the repository at this point in the history
Added a new authorization method to AuthorizationManager that returns AuthorizationResult.

Closes spring-projectsgh-14843
  • Loading branch information
Max Batischev authored and Max Batischev committed Apr 7, 2024
1 parent c8e5fbf commit a368cd1
Show file tree
Hide file tree
Showing 40 changed files with 190 additions and 169 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -22,7 +22,6 @@
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.authorization.ObservationAuthorizationManager;
Expand Down Expand Up @@ -61,8 +60,8 @@ final class DeferringObservationAuthorizationManager<T>
}

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
return this.delegate.get().check(authentication, object);
public AuthorizationResult authorize(Supplier<Authentication> authentication, T object) {
return this.delegate.get().authorize(authentication, object);
}

@Override
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -32,8 +32,8 @@
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
Expand Down Expand Up @@ -221,7 +221,7 @@ private boolean checkLoginPageIsPublic(List<Filter> filters, FilterInvocation lo
AuthorizationManager<HttpServletRequest> authorizationManager = authorizationFilter
.getAuthorizationManager();
try {
AuthorizationDecision decision = authorizationManager.check(() -> TEST, loginRequest.getHttpRequest());
AuthorizationResult decision = authorizationManager.authorize(() -> TEST, loginRequest.getHttpRequest());
return decision != null && decision.isGranted();
}
catch (Exception ex) {
Expand Down Expand Up @@ -252,7 +252,7 @@ private Supplier<Boolean> deriveAnonymousCheck(List<Filter> filters, FilterInvoc
return () -> {
AuthorizationManager<HttpServletRequest> authorizationManager = authorizationFilter
.getAuthorizationManager();
AuthorizationDecision decision = authorizationManager.check(() -> token, loginRequest.getHttpRequest());
AuthorizationResult decision = authorizationManager.authorize(() -> token, loginRequest.getHttpRequest());
return decision != null && decision.isGranted();
};
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -25,6 +25,7 @@
import org.springframework.aop.support.AopUtils;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.core.Authentication;

class PointcutDelegatingAuthorizationManager implements AuthorizationManager<MethodInvocation> {
Expand All @@ -36,15 +37,14 @@ class PointcutDelegatingAuthorizationManager implements AuthorizationManager<Met
}

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
public AuthorizationResult authorize(Supplier<Authentication> authentication, MethodInvocation object) {
for (Map.Entry<Pointcut, AuthorizationManager<MethodInvocation>> entry : this.managers.entrySet()) {
Class<?> targetClass = (object.getThis() != null) ? AopUtils.getTargetClass(object.getThis()) : null;
if (entry.getKey().getClassFilter().matches(targetClass)
&& entry.getKey().getMethodMatcher().matches(object.getMethod(), targetClass)) {
return entry.getValue().check(authentication, object);
return entry.getValue().authorize(authentication, object);
}
}
return new AuthorizationDecision(false);
}

}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2024 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 @@ -21,6 +21,7 @@
import java.util.Map;
import java.util.function.Supplier;

import org.springframework.security.authorization.AuthorizationResult;
import org.w3c.dom.Element;

import org.springframework.beans.BeansException;
Expand Down Expand Up @@ -455,8 +456,7 @@ private ExpressionBasedAuthorizationManager(
}

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication,
MessageAuthorizationContext<?> object) {
public AuthorizationResult authorize(Supplier<Authentication> authentication, MessageAuthorizationContext<?> object) {
EvaluationContext context = this.expressionHandler.createEvaluationContext(authentication, object);
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, context);
return new AuthorizationDecision(granted);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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 @@ -131,15 +131,15 @@ public void configureMvcMatcherAccessAuthorizationManagerWhenNotNullThenVerifyUs
CustomAuthorizationManagerConfig.authorizationManager = mock(AuthorizationManager.class);
this.spring.register(CustomAuthorizationManagerConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk());
verify(CustomAuthorizationManagerConfig.authorizationManager).check(any(), any());
verify(CustomAuthorizationManagerConfig.authorizationManager).authorize(any(), any());
}

@Test
public void configureNoParameterMvcMatcherAccessAuthorizationManagerWhenNotNullThenVerifyUse() throws Exception {
CustomAuthorizationManagerNoParameterConfig.authorizationManager = mock(AuthorizationManager.class);
this.spring.register(CustomAuthorizationManagerNoParameterConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk());
verify(CustomAuthorizationManagerNoParameterConfig.authorizationManager).check(any(), any());
verify(CustomAuthorizationManagerNoParameterConfig.authorizationManager).authorize(any(), any());
}

@Test
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -112,7 +112,7 @@ public void validateCheckLoginPageIsntProtectedThrowsIllegalArgumentException()

@Test
public void validateCheckLoginPageAllowsAnonymous() {
given(this.authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(false));
given(this.authorizationManager.authorize(any(), any())).willReturn(new AuthorizationDecision(false));
this.validator.validate(this.chainAuthorizationFilter);
verify(this.logger).warn("Anonymous access to the login page doesn't appear to be enabled. "
+ "This is almost certainly an error. Please check your configuration allows unauthenticated "
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -90,13 +90,13 @@ public void getWhenUsingAuthorizationManagerThenRedirectsToLogin() throws Except
this.spring.configLocations(this.xml("AuthorizationManager")).autowire();
AuthorizationManager<HttpServletRequest> authorizationManager = this.spring.getContext()
.getBean(AuthorizationManager.class);
given(authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(false));
given(authorizationManager.authorize(any(), any())).willReturn(new AuthorizationDecision(false));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
verify(authorizationManager).check(any(), any());
verify(authorizationManager).authorize(any(), any());
}

@Test
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -168,9 +168,9 @@ public void transactionalAuthorizationManagerMethodsShouldBeSecured() {

@Test
public void targetCustomAuthorizationManagerUsed() {
given(this.mockAuthorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(true));
given(this.mockAuthorizationManager.authorize(any(), any())).willReturn(new AuthorizationDecision(true));
this.targetCustomAuthorizationManager.doSomething();
verify(this.mockAuthorizationManager).check(any(), any());
verify(this.mockAuthorizationManager).authorize(any(), any());
}

@Override
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -39,6 +39,7 @@
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.config.annotation.method.configuration.MethodSecurityService;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
Expand Down Expand Up @@ -463,7 +464,7 @@ public boolean hasPermission(Authentication authentication, Serializable targetI
static class MyAuthorizationManager implements AuthorizationManager<MethodInvocation> {

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
public AuthorizationResult authorize(Supplier<Authentication> authentication, MethodInvocation object) {
return new AuthorizationDecision("bob".equals(authentication.get().getName()));
}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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 @@ -489,11 +489,11 @@ public void sendWhenCustomAuthorizationManagerThenAuthorizesAccordingly() {
this.spring.configLocations(xml("CustomAuthorizationManagerConfig")).autowire();
AuthorizationManager<Message<?>> authorizationManager = this.spring.getContext()
.getBean(AuthorizationManager.class);
given(authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(false));
given(authorizationManager.authorize(any(), any())).willReturn(new AuthorizationDecision(false));
Message<?> message = message("/any");
assertThatExceptionOfType(Exception.class).isThrownBy(send(message))
.withCauseInstanceOf(AccessDeniedException.class);
verify(authorizationManager).check(any(), any());
verify(authorizationManager).authorize(any(), any());
}

private String xml(String configName) {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -106,12 +106,12 @@ public static <T> AuthenticatedAuthorizationManager<T> anonymous() {

/**
* Determines if the current user is authorized according to the given strategy.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@link T} object to check
* @param authentication the {@link Supplier} of the {@link Authentication} to authorize
* @param object the {@link T} object to authorize
* @return an {@link AuthorizationDecision}
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
public AuthorizationResult authorize(Supplier<Authentication> authentication, T object) {
boolean granted = this.authorizationStrategy.isGranted(authentication.get());
return new AuthorizationDecision(granted);
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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 @@ -50,13 +50,12 @@ public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
/**
* Determines if the current user is authorized by evaluating if the
* {@link Authentication} contains any of specified authorities.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param authorities the collection of authority strings to check
* @param authentication the {@link Supplier} of the {@link Authentication} to authorize
* @param authorities the collection of authority strings to authorize
* @return an {@link AuthorityAuthorizationDecision}
*/
@Override
public AuthorityAuthorizationDecision check(Supplier<Authentication> authentication,
Collection<String> authorities) {
public AuthorizationResult authorize(Supplier<Authentication> authentication, Collection<String> authorities) {
boolean granted = isGranted(authentication.get(), authorities);
return new AuthorityAuthorizationDecision(granted, AuthorityUtils.createAuthorityList(authorities));
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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 @@ -26,7 +26,7 @@

/**
* An {@link AuthorizationManager} that determines if the current user is authorized by
* evaluating if the {@link Authentication} contains a specified authority.
* evaluating if the {@link AuthorizationResult} contains a specified authority.
*
* @param <T> the type of object being authorized.
* @author Evgeniy Cheban
Expand Down Expand Up @@ -136,13 +136,13 @@ private static String[] toNamedRolesArray(String rolePrefix, String[] roles) {
/**
* Determines if the current user is authorized by evaluating if the
* {@link Authentication} contains a specified authority.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@link T} object to check
* @return an {@link AuthorizationDecision}
* @param authentication the {@link Supplier} of the {@link Authentication} to authorize
* @param object the {@link T} object to authorize
* @return an {@link AuthorizationResult}
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
return this.delegate.check(authentication, this.authorities);
public AuthorizationResult authorize(Supplier<Authentication> authentication, T object) {
return this.delegate.authorize(authentication, this.authorities);
}

@Override
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2024 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 @@ -39,7 +39,7 @@ public interface AuthorizationManager<T> {
* @throws AccessDeniedException if access is not granted
*/
default void verify(Supplier<Authentication> authentication, T object) {
AuthorizationDecision decision = check(authentication, object);
AuthorizationResult decision = authorize(authentication, object);
if (decision != null && !decision.isGranted()) {
throw new AccessDeniedException("Access Denied");
}
Expand All @@ -50,8 +50,23 @@ default void verify(Supplier<Authentication> authentication, T object) {
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@link T} object to check
* @return an {@link AuthorizationDecision} or null if no decision could be made
* @deprecated Use {{@link #authorize(Supplier, Object)}} instead
*/
@Deprecated(forRemoval = true)
@Nullable
AuthorizationDecision check(Supplier<Authentication> authentication, T object);
default AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
return (AuthorizationDecision) authorize(authentication, object);
}

/**
* Determines if access should be granted for a specific authentication and object.
* @param authentication the {@link Supplier} of the {@link Authentication} to
* authorize
* @param object the {@link T} object to authorize
* @return an {@link AuthorizationResult} or null if no result could be made
* @since 6.3
*/
@Nullable
AuthorizationResult authorize(Supplier<Authentication> authentication, T object);

}

0 comments on commit a368cd1

Please sign in to comment.