Revert "Support SpEL Returning AuthorizationDecision"

This reverts commit 77f2977c55.
This commit is contained in:
Josh Cummings
2024-04-04 11:31:45 -06:00
parent 77f2977c55
commit 0a9c482f62
28 changed files with 199 additions and 520 deletions

View File

@@ -1,70 +0,0 @@
/*
* 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.
* 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.access.expression;
import org.junit.jupiter.api.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ExpressionAuthorizationDecision;
import static org.assertj.core.api.Assertions.assertThat;
public class ExpressionUtilsTests {
private final Object details = new Object();
@Test
public void evaluateWhenAuthorizationDecisionThenReturns() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("#root.returnDecision()");
StandardEvaluationContext context = new StandardEvaluationContext(this);
assertThat(ExpressionUtils.evaluate(expression, context)).isInstanceOf(AuthorizationDecisionDetails.class)
.extracting("details")
.isEqualTo(this.details);
}
@Test
public void evaluateWhenBooleanThenReturnsExpressionAuthorizationDecision() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("#root.returnResult()");
StandardEvaluationContext context = new StandardEvaluationContext(this);
assertThat(ExpressionUtils.evaluate(expression, context)).isInstanceOf(ExpressionAuthorizationDecision.class);
}
public AuthorizationDecision returnDecision() {
return new AuthorizationDecisionDetails(false, this.details);
}
public boolean returnResult() {
return false;
}
static final class AuthorizationDecisionDetails extends AuthorizationDecision {
final Object details;
AuthorizationDecisionDetails(boolean granted, Object details) {
super(granted);
this.details = details;
}
}
}

View File

@@ -19,15 +19,16 @@ package org.springframework.security.authorization.method;
import org.aopalliance.intercept.MethodInvocation;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.mockito.invocation.InvocationOnMock;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.aop.Pointcut;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import static org.assertj.core.api.Assertions.assertThat;
@@ -124,10 +125,10 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("flux")));
given(mockMethodInvocation.proceed()).willReturn(Flux.just("john", "bob"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.postProcessResult(any(), any())).willAnswer(this::masking);
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.empty());
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.check(any(), any()))
.will((invocation) -> Mono.just(createDecision(new MaskingPostProcessor())));
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -143,16 +144,15 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("flux")));
given(mockMethodInvocation.proceed()).willReturn(Flux.just("john", "bob"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.postProcessResult(any(), any())).willAnswer((invocation) -> {
MethodInvocationResult argument = invocation.getArgument(0);
if (!"john".equals(argument.getResult())) {
return monoMasking(invocation);
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.check(any(), any())).willAnswer((invocation) -> {
MethodInvocationResult argument = invocation.getArgument(1);
if ("john".equals(argument.getResult())) {
return Mono.just(new AuthorizationDecision(true));
}
return Mono.just(argument.getResult());
return Mono.just(createDecision(new MaskingPostProcessor()));
});
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.empty());
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -168,10 +168,11 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.postProcessResult(any(), any())).willAnswer(this::masking);
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.empty());
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
PostAuthorizeAuthorizationDecision decision = new PostAuthorizeAuthorizationDecision(false,
new LiteralExpression("1234"), new MaskingPostProcessor());
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.just(decision));
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -186,10 +187,11 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.postProcessResult(any(), any())).willAnswer(this::monoMasking);
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.empty());
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
PostAuthorizeAuthorizationDecision decision = new PostAuthorizeAuthorizationDecision(false,
new LiteralExpression("1234"), new MonoMaskingPostProcessor());
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.just(decision));
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -204,10 +206,11 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.postProcessResult(any(), any())).willReturn(null);
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.empty());
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
PostAuthorizeAuthorizationDecision decision = new PostAuthorizeAuthorizationDecision(false,
new LiteralExpression("1234"), new NullPostProcessor());
given(mockReactiveAuthorizationManager.check(any(), any())).willReturn(Mono.just(decision));
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -235,18 +238,34 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
verify(mockReactiveAuthorizationManager).check(any(), any());
}
private Object masking(InvocationOnMock invocation) {
MethodInvocationResult result = invocation.getArgument(0);
return result.getResult() + "-masked";
private PostAuthorizeAuthorizationDecision createDecision(MethodAuthorizationDeniedPostProcessor postProcessor) {
return new PostAuthorizeAuthorizationDecision(false, new LiteralExpression("1234"), postProcessor);
}
private Object monoMasking(InvocationOnMock invocation) {
MethodInvocationResult result = invocation.getArgument(0);
return Mono.just(result.getResult() + "-masked");
static class MaskingPostProcessor implements MethodAuthorizationDeniedPostProcessor {
@Override
public Object postProcessResult(MethodInvocationResult contextObject, AuthorizationResult result) {
return contextObject.getResult() + "-masked";
}
}
interface HandlingReactiveAuthorizationManager
extends ReactiveAuthorizationManager<MethodInvocationResult>, MethodAuthorizationDeniedPostProcessor {
static class MonoMaskingPostProcessor implements MethodAuthorizationDeniedPostProcessor {
@Override
public Object postProcessResult(MethodInvocationResult contextObject, AuthorizationResult result) {
return Mono.just(contextObject.getResult() + "-masked");
}
}
static class NullPostProcessor implements MethodAuthorizationDeniedPostProcessor {
@Override
public Object postProcessResult(MethodInvocationResult contextObject, AuthorizationResult result) {
return null;
}
}

View File

@@ -23,10 +23,12 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.aop.Pointcut;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import static org.assertj.core.api.Assertions.assertThat;
@@ -123,10 +125,11 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.check(any(), eq(mockMethodInvocation))).willReturn(Mono.empty());
given(mockReactiveAuthorizationManager.handle(any(), any())).willReturn("***");
ReactiveAuthorizationManager<MethodInvocation> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
PreAuthorizeAuthorizationDecision decision = new PreAuthorizeAuthorizationDecision(false,
new LiteralExpression("1234"), new MaskingPostProcessor());
given(mockReactiveAuthorizationManager.check(any(), eq(mockMethodInvocation))).willReturn(Mono.just(decision));
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -141,10 +144,11 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.check(any(), eq(mockMethodInvocation))).willReturn(Mono.empty());
given(mockReactiveAuthorizationManager.handle(any(), any())).willReturn(Mono.just("***"));
ReactiveAuthorizationManager<MethodInvocation> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
PreAuthorizeAuthorizationDecision decision = new PreAuthorizeAuthorizationDecision(false,
new LiteralExpression("1234"), new MonoMaskingPostProcessor());
given(mockReactiveAuthorizationManager.check(any(), eq(mockMethodInvocation))).willReturn(Mono.just(decision));
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -159,10 +163,11 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests {
MethodInvocation mockMethodInvocation = spy(
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("flux")));
given(mockMethodInvocation.proceed()).willReturn(Flux.just("john", "bob"));
HandlingReactiveAuthorizationManager mockReactiveAuthorizationManager = mock(
HandlingReactiveAuthorizationManager.class);
given(mockReactiveAuthorizationManager.check(any(), eq(mockMethodInvocation))).willReturn(Mono.empty());
given(mockReactiveAuthorizationManager.handle(any(), any())).willReturn(Mono.just("***"));
ReactiveAuthorizationManager<MethodInvocation> mockReactiveAuthorizationManager = mock(
ReactiveAuthorizationManager.class);
PreAuthorizeAuthorizationDecision decision = new PreAuthorizeAuthorizationDecision(false,
new LiteralExpression("1234"), new MonoMaskingPostProcessor());
given(mockReactiveAuthorizationManager.check(any(), eq(mockMethodInvocation))).willReturn(Mono.just(decision));
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(
Pointcut.TRUE, mockReactiveAuthorizationManager);
Object result = interceptor.invoke(mockMethodInvocation);
@@ -209,8 +214,21 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests {
verify(mockReactiveAuthorizationManager).check(any(), eq(mockMethodInvocation));
}
interface HandlingReactiveAuthorizationManager
extends ReactiveAuthorizationManager<MethodInvocation>, MethodAuthorizationDeniedHandler {
static class MaskingPostProcessor implements MethodAuthorizationDeniedHandler {
@Override
public Object handle(MethodInvocation methodInvocation, AuthorizationResult result) {
return "***";
}
}
static class MonoMaskingPostProcessor implements MethodAuthorizationDeniedHandler {
@Override
public Object handle(MethodInvocation methodInvocation, AuthorizationResult result) {
return Mono.just("***");
}
}