SpEL Expressions Support Returning AuthorizationManager
Closes gh-17936
This commit is contained in:
+15
@@ -16,14 +16,19 @@
|
||||
|
||||
package org.springframework.security.authorization.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.security.authorization.AuthorizationDeniedException;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.authorization.ExpressionAuthorizationDecision;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
final class ExpressionUtils {
|
||||
|
||||
@@ -31,8 +36,18 @@ final class ExpressionUtils {
|
||||
}
|
||||
|
||||
static @Nullable AuthorizationResult evaluate(Expression expr, EvaluationContext ctx) {
|
||||
return evaluate(expr, ctx, () -> null, null);
|
||||
}
|
||||
|
||||
static <T> @Nullable AuthorizationResult evaluate(Expression expr, EvaluationContext ctx,
|
||||
Supplier<? extends @Nullable Authentication> authentication, @Nullable T context) {
|
||||
try {
|
||||
Object result = expr.getValue(ctx);
|
||||
if (result instanceof AuthorizationManager<?> manager) {
|
||||
Assert.notNull(authentication, "authentication supplier cannot be null");
|
||||
Assert.notNull(context, "context cannot be null");
|
||||
return ((AuthorizationManager<T>) manager).authorize(authentication, context);
|
||||
}
|
||||
if (result instanceof AuthorizationResult decision) {
|
||||
return decision;
|
||||
}
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ public final class PostAuthorizeAuthorizationManager
|
||||
MethodSecurityExpressionHandler expressionHandler = this.registry.getExpressionHandler();
|
||||
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, mi.getMethodInvocation());
|
||||
expressionHandler.setReturnObject(mi.getResult(), ctx);
|
||||
return ExpressionUtils.evaluate(attribute.getExpression(), ctx);
|
||||
return ExpressionUtils.evaluate(attribute.getExpression(), ctx, authentication, mi);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ public final class PostAuthorizeReactiveAuthorizationManager
|
||||
return authentication
|
||||
.map((auth) -> expressionHandler.createEvaluationContext(auth, mi))
|
||||
.doOnNext((ctx) -> expressionHandler.setReturnObject(result.getResult(), ctx))
|
||||
.flatMap((ctx) -> ReactiveExpressionUtils.evaluate(attribute.getExpression(), ctx))
|
||||
.flatMap((ctx) -> ReactiveExpressionUtils.evaluate(attribute.getExpression(), ctx, authentication, result))
|
||||
.cast(AuthorizationResult.class);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ public final class PreAuthorizeAuthorizationManager
|
||||
return null;
|
||||
}
|
||||
EvaluationContext ctx = this.registry.getExpressionHandler().createEvaluationContext(authentication, mi);
|
||||
return ExpressionUtils.evaluate(attribute.getExpression(), ctx);
|
||||
return ExpressionUtils.evaluate(attribute.getExpression(), ctx, authentication, mi);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ public final class PreAuthorizeReactiveAuthorizationManager
|
||||
// @formatter:off
|
||||
return authentication
|
||||
.map((auth) -> this.registry.getExpressionHandler().createEvaluationContext(auth, mi))
|
||||
.flatMap((ctx) -> ReactiveExpressionUtils.evaluate(attribute.getExpression(), ctx))
|
||||
.flatMap((ctx) -> ReactiveExpressionUtils.evaluate(attribute.getExpression(), ctx, authentication, mi))
|
||||
.cast(AuthorizationResult.class);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
+12
@@ -24,6 +24,9 @@ import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.security.authorization.AuthorizationResult;
|
||||
import org.springframework.security.authorization.ExpressionAuthorizationDecision;
|
||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* For internal use only, as this contract is likely to change.
|
||||
@@ -34,6 +37,11 @@ import org.springframework.security.authorization.ExpressionAuthorizationDecisio
|
||||
final class ReactiveExpressionUtils {
|
||||
|
||||
static Mono<AuthorizationResult> evaluate(Expression expr, EvaluationContext ctx) {
|
||||
return evaluate(expr, ctx, Mono.empty(), null);
|
||||
}
|
||||
|
||||
static <T> Mono<AuthorizationResult> evaluate(Expression expr, EvaluationContext ctx,
|
||||
Mono<Authentication> authentication, @Nullable T context) {
|
||||
return Mono.defer(() -> {
|
||||
Object value;
|
||||
try {
|
||||
@@ -43,6 +51,10 @@ final class ReactiveExpressionUtils {
|
||||
return Mono.error(() -> new IllegalArgumentException(
|
||||
"Failed to evaluate expression '" + expr.getExpressionString() + "'", ex));
|
||||
}
|
||||
if (value instanceof ReactiveAuthorizationManager<?> manager) {
|
||||
Assert.notNull(context, "context cannot be null");
|
||||
return ((ReactiveAuthorizationManager<T>) manager).authorize(authentication, context);
|
||||
}
|
||||
if (value instanceof Mono<?> mono) {
|
||||
return mono.flatMap((data) -> adapt(expr, data));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user