Skip to content

Commit

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

Closes spring-projectsgh-14843
  • Loading branch information
Max Batischev authored and Max Batischev committed Apr 7, 2024
1 parent 9b79f68 commit 011fea2
Show file tree
Hide file tree
Showing 37 changed files with 240 additions and 148 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 @@ -21,8 +21,8 @@
import io.micrometer.observation.ObservationRegistry;

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;
import org.springframework.security.core.Authentication;
import org.springframework.util.function.SingletonSupplier;
Expand All @@ -43,8 +43,8 @@ final class DeferringObservationAuthorizationManager<T> implements Authorization
}

@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);
}

}
@@ -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,8 @@ 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 +253,8 @@ 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,12 +37,12 @@ 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);
Expand Down
@@ -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 Down Expand Up @@ -49,6 +49,7 @@
import org.springframework.security.access.vote.ConsensusBased;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.config.Elements;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -455,7 +456,7 @@ private ExpressionBasedAuthorizationManager(
}

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication,
public AuthorizationResult authorize(Supplier<Authentication> authentication,
MessageAuthorizationContext<?> object) {
EvaluationContext context = this.expressionHandler.createEvaluationContext(authentication, object);
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, context);
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-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,13 @@ 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,13 @@ 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 2024-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 @@ -136,13 +136,14 @@ 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 @@ -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);

}
@@ -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 @@ -56,9 +56,9 @@ public static <T> AuthorizationManager<T> anyOf(AuthorizationManager<T>... manag
public static <T> AuthorizationManager<T> anyOf(AuthorizationDecision allAbstainDefaultDecision,
AuthorizationManager<T>... managers) {
return (authentication, object) -> {
List<AuthorizationDecision> decisions = new ArrayList<>();
List<AuthorizationResult> decisions = new ArrayList<>();
for (AuthorizationManager<T> manager : managers) {
AuthorizationDecision decision = manager.check(authentication, object);
AuthorizationResult decision = manager.authorize(authentication, object);
if (decision == null) {
continue;
}
Expand Down Expand Up @@ -102,9 +102,9 @@ public static <T> AuthorizationManager<T> allOf(AuthorizationManager<T>... manag
public static <T> AuthorizationManager<T> allOf(AuthorizationDecision allAbstainDefaultDecision,
AuthorizationManager<T>... managers) {
return (authentication, object) -> {
List<AuthorizationDecision> decisions = new ArrayList<>();
List<AuthorizationResult> decisions = new ArrayList<>();
for (AuthorizationManager<T> manager : managers) {
AuthorizationDecision decision = manager.check(authentication, object);
AuthorizationResult decision = manager.authorize(authentication, object);
if (decision == null) {
continue;
}
Expand All @@ -131,7 +131,7 @@ public static <T> AuthorizationManager<T> allOf(AuthorizationDecision allAbstain
*/
public static <T> AuthorizationManager<T> not(AuthorizationManager<T> manager) {
return (authentication, object) -> {
AuthorizationDecision decision = manager.check(authentication, object);
AuthorizationResult decision = manager.authorize(authentication, object);
if (decision == null) {
return null;
}
Expand All @@ -144,9 +144,9 @@ private AuthorizationManagers() {

private static final class CompositeAuthorizationDecision extends AuthorizationDecision {

private final List<AuthorizationDecision> decisions;
private final List<AuthorizationResult> decisions;

private CompositeAuthorizationDecision(boolean granted, List<AuthorizationDecision> decisions) {
private CompositeAuthorizationDecision(boolean granted, List<AuthorizationResult> decisions) {
super(granted);
this.decisions = decisions;
}
Expand All @@ -160,9 +160,9 @@ public String toString() {

private static final class NotAuthorizationDecision extends AuthorizationDecision {

private final AuthorizationDecision decision;
private final AuthorizationResult decision;

private NotAuthorizationDecision(AuthorizationDecision decision) {
private NotAuthorizationDecision(AuthorizationResult decision) {
super(!decision.isGranted());
this.decision = decision;
}
Expand Down

0 comments on commit 011fea2

Please sign in to comment.