createEvaluationContext should defer lookup of Authentication
- Added createEvaluationContext method that accepts Supplier<Authentication> - Refactored classes that use EvaluationContext to use lazy initialization of Authentication Closes gh-9667
This commit is contained in:
committed by
Josh Cummings
parent
2be141f800
commit
5540bbcf0b
+19
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.security.web.access.expression;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
@@ -39,9 +43,24 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
|
||||
@Override
|
||||
public EvaluationContext createEvaluationContext(Supplier<Authentication> authentication,
|
||||
RequestAuthorizationContext context) {
|
||||
WebSecurityExpressionRoot root = createSecurityExpressionRoot(authentication, context);
|
||||
StandardEvaluationContext ctx = new StandardEvaluationContext(root);
|
||||
ctx.setBeanResolver(getBeanResolver());
|
||||
context.getVariables().forEach(ctx::setVariable);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
|
||||
RequestAuthorizationContext context) {
|
||||
return createSecurityExpressionRoot(() -> authentication, context);
|
||||
}
|
||||
|
||||
private WebSecurityExpressionRoot createSecurityExpressionRoot(Supplier<Authentication> authentication,
|
||||
RequestAuthorizationContext context) {
|
||||
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, context.getRequest());
|
||||
root.setRoleHierarchy(getRoleHierarchy());
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
|
||||
+1
-5
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.security.web.access.expression;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
@@ -72,10 +71,7 @@ public final class WebExpressionAuthorizationManager implements AuthorizationMan
|
||||
*/
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
|
||||
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), context);
|
||||
for (Map.Entry<String, String> entry : context.getVariables().entrySet()) {
|
||||
ctx.setVariable(entry.getKey(), entry.getValue());
|
||||
}
|
||||
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, context);
|
||||
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
|
||||
return new ExpressionAuthorizationDecision(granted, this.expression);
|
||||
}
|
||||
|
||||
+7
-6
@@ -16,8 +16,9 @@
|
||||
|
||||
package org.springframework.security.web.access.expression;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
@@ -36,17 +37,17 @@ public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
|
||||
public final HttpServletRequest request;
|
||||
|
||||
public WebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
|
||||
this(a, fi.getRequest());
|
||||
this(() -> a, fi.getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for the given {@link Authentication} and
|
||||
* {@link HttpServletRequest}.
|
||||
* @param authentication the {@link Authentication} to use
|
||||
* Creates an instance for the given {@link Supplier} of the {@link Authentication}
|
||||
* and {@link HttpServletRequest}.
|
||||
* @param authentication the {@link Supplier} of the {@link Authentication} to use
|
||||
* @param request the {@link HttpServletRequest} to use
|
||||
* @since 5.8
|
||||
*/
|
||||
public WebSecurityExpressionRoot(Authentication authentication, HttpServletRequest request) {
|
||||
public WebSecurityExpressionRoot(Supplier<Authentication> authentication, HttpServletRequest request) {
|
||||
super(authentication);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
+20
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.security.web.access.expression;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -28,7 +31,9 @@ import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.expression.SecurityExpressionRoot;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -36,8 +41,10 @@ import org.springframework.security.web.access.intercept.RequestAuthorizationCon
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class DefaultHttpSecurityExpressionHandlerTests {
|
||||
@@ -91,4 +98,16 @@ public class DefaultHttpSecurityExpressionHandlerTests {
|
||||
verify(this.trustResolver).isAnonymous(this.authentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createEvaluationContextSupplierAuthentication() {
|
||||
Supplier<Authentication> mockAuthenticationSupplier = mock(Supplier.class);
|
||||
given(mockAuthenticationSupplier.get()).willReturn(this.authentication);
|
||||
EvaluationContext context = this.handler.createEvaluationContext(mockAuthenticationSupplier, this.context);
|
||||
verifyNoInteractions(mockAuthenticationSupplier);
|
||||
assertThat(context.getRootObject()).extracting(TypedValue::getValue)
|
||||
.asInstanceOf(InstanceOfAssertFactories.type(WebSecurityExpressionRoot.class))
|
||||
.extracting(SecurityExpressionRoot::getAuthentication).isEqualTo(this.authentication);
|
||||
verify(mockAuthenticationSupplier).get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user