Skip to content

Commit

Permalink
Add support expressions in MethodAuthorizationDeniedHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Batischev authored and Max Batischev committed Apr 15, 2024
1 parent bf478d9 commit c42d175
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 3 deletions.
Expand Up @@ -42,4 +42,10 @@
*/
String value();

/**
* @return Spring-EL expression to be evaluated when handling denied authorization
* @since 6.3
*/
String handlerExpression() default "";

}
@@ -0,0 +1,52 @@
/*
* 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.authorization.method;

import org.aopalliance.intercept.MethodInvocation;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.util.Assert;

/**
* {@link MethodAuthorizationDeniedHandler} implementation, that return authorization
* result, based on SpEL expression.
*
* @author Max Batischev
* @since 6.3
*/
final class ExpressionMethodAuthorizationDeniedHandler implements MethodAuthorizationDeniedHandler {

private final String expression;

private final ExpressionParser expressionParser;

ExpressionMethodAuthorizationDeniedHandler(String expression, ExpressionParser expressionParser) {
Assert.notNull(expressionParser, "expressionParser cannot be null");
Assert.notNull(expression, "expression cannot be null");
this.expressionParser = expressionParser;
this.expression = expression;
}

@Override
public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) {
Expression expression = this.expressionParser.parseExpression(this.expression);
return expression.getValue();
}

}
Expand Up @@ -28,6 +28,7 @@
import org.springframework.expression.Expression;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
* For internal use only, as this contract is likely to change.
Expand Down Expand Up @@ -55,11 +56,13 @@ ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
return ExpressionAttribute.NULL_ATTRIBUTE;
}
Expression expression = getExpressionHandler().getExpressionParser().parseExpression(preAuthorize.value());
MethodAuthorizationDeniedHandler handler = resolveHandler(method, targetClass);
MethodAuthorizationDeniedHandler handler = resolveHandler(method, targetClass,
preAuthorize.handlerExpression());
return new PreAuthorizeExpressionAttribute(expression, handler);
}

private MethodAuthorizationDeniedHandler resolveHandler(Method method, Class<?> targetClass) {
private MethodAuthorizationDeniedHandler resolveHandler(Method method, Class<?> targetClass,
String handlerExpression) {
Function<AnnotatedElement, HandleAuthorizationDenied> lookup = AuthorizationAnnotationUtils
.withDefaults(HandleAuthorizationDenied.class);
HandleAuthorizationDenied deniedHandler = lookup.apply(method);
Expand All @@ -70,6 +73,10 @@ private MethodAuthorizationDeniedHandler resolveHandler(Method method, Class<?>
if (deniedHandler != null) {
return this.handlerResolver.apply(deniedHandler.handlerClass());
}
if (StringUtils.hasText(handlerExpression)) {
return new ExpressionMethodAuthorizationDeniedHandler(handlerExpression,
getExpressionHandler().getExpressionParser());
}
return this.defaultHandler;
}

Expand Down
Expand Up @@ -21,6 +21,7 @@
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import org.springframework.aop.TargetClassAware;
import org.springframework.core.annotation.AnnotationConfigurationException;
Expand All @@ -31,6 +32,7 @@
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.core.Authentication;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -156,6 +158,16 @@ public void checkRequiresUserWhenMethodsFromInheritThenApplies() throws Exceptio
assertThat(decision.isGranted()).isTrue();
}

@Test
public void handleDeniedInvocationWhenHandlerExpressionIsPresentThenReturnEvaluatedValue() throws Exception {
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
AuthorizationResult authorizationResult = Mockito.mock(AuthorizationResult.class);
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
Object decision = manager.handleDeniedInvocation(methodInvocation, authorizationResult);
assertThat(decision).isEqualTo("deny");
}

@PreAuthorize("hasRole('USER')")
public static class PreAuthorizeClass extends ParentClass {

Expand All @@ -175,7 +187,7 @@ public void doSomething() {

}

@PreAuthorize("#s == 'grant'")
@PreAuthorize(value = "#s == 'grant'", handlerExpression = "'deny'")
public String doSomethingString(String s) {
return s;
}
Expand Down

0 comments on commit c42d175

Please sign in to comment.