Explorar o código

Merge branch '6.0.x' into 6.1.x

Closes gh-14111
Josh Cummings hai 1 ano
pai
achega
f295e9d28f

+ 12 - 15
core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -51,8 +51,7 @@ import org.springframework.util.Assert;
 public final class AuthorizationManagerAfterMethodInterceptor
 		implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
 
-	private Supplier<Authentication> authentication = getAuthentication(
-			SecurityContextHolder.getContextHolderStrategy());
+	private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
 
 	private final Log logger = LogFactory.getLog(this.getClass());
 
@@ -170,14 +169,14 @@ public final class AuthorizationManagerAfterMethodInterceptor
 	 * @since 5.8
 	 */
 	public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
-		this.authentication = getAuthentication(strategy);
+		this.securityContextHolderStrategy = () -> strategy;
 	}
 
 	private void attemptAuthorization(MethodInvocation mi, Object result) {
 		this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
 		MethodInvocationResult object = new MethodInvocationResult(mi, result);
-		AuthorizationDecision decision = this.authorizationManager.check(this.authentication, object);
-		this.eventPublisher.publishAuthorizationEvent(this.authentication, object, decision);
+		AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, object);
+		this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, object, decision);
 		if (decision != null && !decision.isGranted()) {
 			this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
 					+ this.authorizationManager + " and decision " + decision));
@@ -186,15 +185,13 @@ public final class AuthorizationManagerAfterMethodInterceptor
 		this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
 	}
 
-	private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
-		return () -> {
-			Authentication authentication = strategy.getContext().getAuthentication();
-			if (authentication == null) {
-				throw new AuthenticationCredentialsNotFoundException(
-						"An Authentication object was not found in the SecurityContext");
-			}
-			return authentication;
-		};
+	private Authentication getAuthentication() {
+		Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
+		if (authentication == null) {
+			throw new AuthenticationCredentialsNotFoundException(
+					"An Authentication object was not found in the SecurityContext");
+		}
+		return authentication;
 	}
 
 	private static <T> void noPublish(Supplier<Authentication> authentication, T object,

+ 12 - 15
core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -55,8 +55,7 @@ import org.springframework.util.Assert;
 public final class AuthorizationManagerBeforeMethodInterceptor
 		implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
 
-	private Supplier<Authentication> authentication = getAuthentication(
-			SecurityContextHolder.getContextHolderStrategy());
+	private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
 
 	private final Log logger = LogFactory.getLog(this.getClass());
 
@@ -244,13 +243,13 @@ public final class AuthorizationManagerBeforeMethodInterceptor
 	 * @since 5.8
 	 */
 	public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
-		this.authentication = getAuthentication(securityContextHolderStrategy);
+		this.securityContextHolderStrategy = () -> securityContextHolderStrategy;
 	}
 
 	private void attemptAuthorization(MethodInvocation mi) {
 		this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
-		AuthorizationDecision decision = this.authorizationManager.check(this.authentication, mi);
-		this.eventPublisher.publishAuthorizationEvent(this.authentication, mi, decision);
+		AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, mi);
+		this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, mi, decision);
 		if (decision != null && !decision.isGranted()) {
 			this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
 					+ this.authorizationManager + " and decision " + decision));
@@ -259,15 +258,13 @@ public final class AuthorizationManagerBeforeMethodInterceptor
 		this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
 	}
 
-	private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
-		return () -> {
-			Authentication authentication = strategy.getContext().getAuthentication();
-			if (authentication == null) {
-				throw new AuthenticationCredentialsNotFoundException(
-						"An Authentication object was not found in the SecurityContext");
-			}
-			return authentication;
-		};
+	private Authentication getAuthentication() {
+		Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
+		if (authentication == null) {
+			throw new AuthenticationCredentialsNotFoundException(
+					"An Authentication object was not found in the SecurityContext");
+		}
+		return authentication;
 	}
 
 	private static <T> void noPublish(Supplier<Authentication> authentication, T object,

+ 11 - 14
core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -46,8 +46,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
 public final class PostFilterAuthorizationMethodInterceptor
 		implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
 
-	private Supplier<Authentication> authentication = getAuthentication(
-			SecurityContextHolder.getContextHolderStrategy());
+	private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
 
 	private PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
 
@@ -108,7 +107,7 @@ public final class PostFilterAuthorizationMethodInterceptor
 	 * @since 5.8
 	 */
 	public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
-		this.authentication = getAuthentication(strategy);
+		this.securityContextHolderStrategy = () -> strategy;
 	}
 
 	/**
@@ -125,19 +124,17 @@ public final class PostFilterAuthorizationMethodInterceptor
 			return returnedObject;
 		}
 		MethodSecurityExpressionHandler expressionHandler = this.registry.getExpressionHandler();
-		EvaluationContext ctx = expressionHandler.createEvaluationContext(this.authentication, mi);
+		EvaluationContext ctx = expressionHandler.createEvaluationContext(this::getAuthentication, mi);
 		return expressionHandler.filter(returnedObject, attribute.getExpression(), ctx);
 	}
 
-	private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
-		return () -> {
-			Authentication authentication = strategy.getContext().getAuthentication();
-			if (authentication == null) {
-				throw new AuthenticationCredentialsNotFoundException(
-						"An Authentication object was not found in the SecurityContext");
-			}
-			return authentication;
-		};
+	private Authentication getAuthentication() {
+		Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
+		if (authentication == null) {
+			throw new AuthenticationCredentialsNotFoundException(
+					"An Authentication object was not found in the SecurityContext");
+		}
+		return authentication;
 	}
 
 }

+ 11 - 14
core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -47,8 +47,7 @@ import org.springframework.util.StringUtils;
 public final class PreFilterAuthorizationMethodInterceptor
 		implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
 
-	private Supplier<Authentication> authentication = getAuthentication(
-			SecurityContextHolder.getContextHolderStrategy());
+	private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
 
 	private PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
 
@@ -109,7 +108,7 @@ public final class PreFilterAuthorizationMethodInterceptor
 	 * @since 5.8
 	 */
 	public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
-		this.authentication = getAuthentication(strategy);
+		this.securityContextHolderStrategy = () -> strategy;
 	}
 
 	/**
@@ -124,7 +123,7 @@ public final class PreFilterAuthorizationMethodInterceptor
 			return mi.proceed();
 		}
 		MethodSecurityExpressionHandler expressionHandler = this.registry.getExpressionHandler();
-		EvaluationContext ctx = expressionHandler.createEvaluationContext(this.authentication, mi);
+		EvaluationContext ctx = expressionHandler.createEvaluationContext(this::getAuthentication, mi);
 		Object filterTarget = findFilterTarget(attribute.getFilterTarget(), ctx, mi);
 		expressionHandler.filter(filterTarget, attribute.getExpression(), ctx);
 		return mi.proceed();
@@ -150,15 +149,13 @@ public final class PreFilterAuthorizationMethodInterceptor
 		return filterTarget;
 	}
 
-	private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
-		return () -> {
-			Authentication authentication = strategy.getContext().getAuthentication();
-			if (authentication == null) {
-				throw new AuthenticationCredentialsNotFoundException(
-						"An Authentication object was not found in the SecurityContext");
-			}
-			return authentication;
-		};
+	private Authentication getAuthentication() {
+		Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
+		if (authentication == null) {
+			throw new AuthenticationCredentialsNotFoundException(
+					"An Authentication object was not found in the SecurityContext");
+		}
+		return authentication;
 	}
 
 }

+ 21 - 1
core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -29,6 +29,7 @@ import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.authorization.AuthorizationEventPublisher;
 import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -91,6 +92,25 @@ public class AuthorizationManagerAfterMethodInterceptorTests {
 		verify(strategy).getContext();
 	}
 
+	// gh-12877
+	@Test
+	public void afterWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
+		SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
+		Authentication authentication = new TestingAuthenticationToken("john", "password",
+				AuthorityUtils.createAuthorityList("authority"));
+		given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
+		MethodInvocation invocation = mock(MethodInvocation.class);
+		AuthorizationManager<MethodInvocationResult> authorizationManager = AuthenticatedAuthorizationManager
+			.authenticated();
+		AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
+				Pointcut.TRUE, authorizationManager);
+		SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
+		SecurityContextHolder.setContextHolderStrategy(strategy);
+		advice.invoke(invocation);
+		verify(strategy).getContext();
+		SecurityContextHolder.setContextHolderStrategy(saved);
+	}
+
 	@Test
 	public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
 		AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(

+ 19 - 1
core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -87,6 +87,24 @@ public class AuthorizationManagerBeforeMethodInterceptorTests {
 		verify(strategy).getContext();
 	}
 
+	// gh-12877
+	@Test
+	public void beforeWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
+		SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
+		Authentication authentication = new TestingAuthenticationToken("john", "password",
+				AuthorityUtils.createAuthorityList("authority"));
+		given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
+		MethodInvocation invocation = mock(MethodInvocation.class);
+		AuthorizationManager<MethodInvocation> authorizationManager = AuthenticatedAuthorizationManager.authenticated();
+		AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
+				Pointcut.TRUE, authorizationManager);
+		SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
+		SecurityContextHolder.setContextHolderStrategy(strategy);
+		advice.invoke(invocation);
+		verify(strategy).getContext();
+		SecurityContextHolder.setContextHolderStrategy(saved);
+	}
+
 	@Test
 	public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
 		AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(

+ 24 - 1
core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -147,6 +147,29 @@ public class PostFilterAuthorizationMethodInterceptorTests {
 		verify(strategy).getContext();
 	}
 
+	// gh-12877
+	@Test
+	public void postFilterWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
+		SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
+		Authentication authentication = new TestingAuthenticationToken("john", "password",
+				AuthorityUtils.createAuthorityList("authority"));
+		given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
+		String[] array = { "john", "bob" };
+		MockMethodInvocation invocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+				"doSomethingArrayAuthentication", new Class[] { String[].class }, new Object[] { array }) {
+			@Override
+			public Object proceed() {
+				return array;
+			}
+		};
+		PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
+		SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
+		SecurityContextHolder.setContextHolderStrategy(strategy);
+		advice.invoke(invocation);
+		verify(strategy).getContext();
+		SecurityContextHolder.setContextHolderStrategy(saved);
+	}
+
 	@PostFilter("filterObject == 'john'")
 	public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
 

+ 21 - 1
core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -204,6 +204,26 @@ public class PreFilterAuthorizationMethodInterceptorTests {
 		verify(strategy).getContext();
 	}
 
+	// gh-12877
+	@Test
+	public void preFilterWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
+		SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
+		Authentication authentication = new TestingAuthenticationToken("john", "password",
+				AuthorityUtils.createAuthorityList("authority"));
+		given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
+		List<String> list = new ArrayList<>();
+		list.add("john");
+		list.add("bob");
+		MockMethodInvocation invocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+				"doSomethingArrayFilterAuthentication", new Class[] { List.class }, new Object[] { list });
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
+		SecurityContextHolder.setContextHolderStrategy(strategy);
+		advice.invoke(invocation);
+		verify(strategy).getContext();
+		SecurityContextHolder.setContextHolderStrategy(saved);
+	}
+
 	@PreFilter("filterObject == 'john'")
 	public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {