Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/6.1.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
jzheaux committed Nov 7, 2023
2 parents 672d86c + f295e9d commit 24abf45
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -51,8 +51,7 @@
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());

Expand Down Expand Up @@ -170,14 +169,14 @@ public boolean isPerInstance() {
* @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));
Expand All @@ -186,15 +185,13 @@ private void attemptAuthorization(MethodInvocation mi, Object result) {
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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -55,8 +55,7 @@
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());

Expand Down Expand Up @@ -244,13 +243,13 @@ public boolean isPerInstance() {
* @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));
Expand All @@ -259,15 +258,13 @@ private void attemptAuthorization(MethodInvocation mi) {
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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -46,8 +46,7 @@
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();

Expand Down Expand Up @@ -108,7 +107,7 @@ public boolean isPerInstance() {
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.authentication = getAuthentication(strategy);
this.securityContextHolderStrategy = () -> strategy;
}

/**
Expand All @@ -125,19 +124,17 @@ public Object invoke(MethodInvocation mi) throws Throwable {
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;
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -47,8 +47,7 @@
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();

Expand Down Expand Up @@ -109,7 +108,7 @@ public boolean isPerInstance() {
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.authentication = getAuthentication(strategy);
this.securityContextHolderStrategy = () -> strategy;
}

/**
Expand All @@ -124,7 +123,7 @@ public Object invoke(MethodInvocation mi) throws Throwable {
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();
Expand All @@ -150,15 +149,13 @@ private Object findFilterTarget(String filterTargetName, EvaluationContext ctx,
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;
}

}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -29,6 +29,7 @@
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;
Expand Down Expand Up @@ -91,6 +92,25 @@ public void afterWhenMockSecurityContextHolderStrategyThenUses() throws Throwabl
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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -87,6 +87,24 @@ public void beforeWhenMockSecurityContextHolderStrategyThenUses() throws Throwab
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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -147,6 +147,29 @@ public Object proceed() {
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 {

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -204,6 +204,26 @@ public void preFilterWhenMockSecurityContextHolderStrategyThenUses() throws Thro
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 {

Expand Down

0 comments on commit 24abf45

Please sign in to comment.