Skip to content

Commit bb354f1

Browse files
committed
Merge branch '5.8.x' into 6.0.x
Closes gh-14110
2 parents b588cea + 11a2189 commit bb354f1

8 files changed

+131
-62
lines changed

core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -51,8 +51,7 @@
5151
public final class AuthorizationManagerAfterMethodInterceptor
5252
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
5353

54-
private Supplier<Authentication> authentication = getAuthentication(
55-
SecurityContextHolder.getContextHolderStrategy());
54+
private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
5655

5756
private final Log logger = LogFactory.getLog(this.getClass());
5857

@@ -170,14 +169,14 @@ public boolean isPerInstance() {
170169
* @since 5.8
171170
*/
172171
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
173-
this.authentication = getAuthentication(strategy);
172+
this.securityContextHolderStrategy = () -> strategy;
174173
}
175174

176175
private void attemptAuthorization(MethodInvocation mi, Object result) {
177176
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
178177
MethodInvocationResult object = new MethodInvocationResult(mi, result);
179-
AuthorizationDecision decision = this.authorizationManager.check(this.authentication, object);
180-
this.eventPublisher.publishAuthorizationEvent(this.authentication, object, decision);
178+
AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, object);
179+
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, object, decision);
181180
if (decision != null && !decision.isGranted()) {
182181
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
183182
+ this.authorizationManager + " and decision " + decision));
@@ -186,15 +185,13 @@ private void attemptAuthorization(MethodInvocation mi, Object result) {
186185
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
187186
}
188187

189-
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
190-
return () -> {
191-
Authentication authentication = strategy.getContext().getAuthentication();
192-
if (authentication == null) {
193-
throw new AuthenticationCredentialsNotFoundException(
194-
"An Authentication object was not found in the SecurityContext");
195-
}
196-
return authentication;
197-
};
188+
private Authentication getAuthentication() {
189+
Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
190+
if (authentication == null) {
191+
throw new AuthenticationCredentialsNotFoundException(
192+
"An Authentication object was not found in the SecurityContext");
193+
}
194+
return authentication;
198195
}
199196

200197
private static <T> void noPublish(Supplier<Authentication> authentication, T object,

core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -55,8 +55,7 @@
5555
public final class AuthorizationManagerBeforeMethodInterceptor
5656
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
5757

58-
private Supplier<Authentication> authentication = getAuthentication(
59-
SecurityContextHolder.getContextHolderStrategy());
58+
private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
6059

6160
private final Log logger = LogFactory.getLog(this.getClass());
6261

@@ -244,13 +243,13 @@ public boolean isPerInstance() {
244243
* @since 5.8
245244
*/
246245
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
247-
this.authentication = getAuthentication(securityContextHolderStrategy);
246+
this.securityContextHolderStrategy = () -> securityContextHolderStrategy;
248247
}
249248

250249
private void attemptAuthorization(MethodInvocation mi) {
251250
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
252-
AuthorizationDecision decision = this.authorizationManager.check(this.authentication, mi);
253-
this.eventPublisher.publishAuthorizationEvent(this.authentication, mi, decision);
251+
AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, mi);
252+
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, mi, decision);
254253
if (decision != null && !decision.isGranted()) {
255254
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
256255
+ this.authorizationManager + " and decision " + decision));
@@ -259,15 +258,13 @@ private void attemptAuthorization(MethodInvocation mi) {
259258
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
260259
}
261260

262-
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
263-
return () -> {
264-
Authentication authentication = strategy.getContext().getAuthentication();
265-
if (authentication == null) {
266-
throw new AuthenticationCredentialsNotFoundException(
267-
"An Authentication object was not found in the SecurityContext");
268-
}
269-
return authentication;
270-
};
261+
private Authentication getAuthentication() {
262+
Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
263+
if (authentication == null) {
264+
throw new AuthenticationCredentialsNotFoundException(
265+
"An Authentication object was not found in the SecurityContext");
266+
}
267+
return authentication;
271268
}
272269

273270
private static <T> void noPublish(Supplier<Authentication> authentication, T object,

core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -46,8 +46,7 @@
4646
public final class PostFilterAuthorizationMethodInterceptor
4747
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
4848

49-
private Supplier<Authentication> authentication = getAuthentication(
50-
SecurityContextHolder.getContextHolderStrategy());
49+
private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
5150

5251
private PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
5352

@@ -108,7 +107,7 @@ public boolean isPerInstance() {
108107
* @since 5.8
109108
*/
110109
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
111-
this.authentication = getAuthentication(strategy);
110+
this.securityContextHolderStrategy = () -> strategy;
112111
}
113112

114113
/**
@@ -125,19 +124,17 @@ public Object invoke(MethodInvocation mi) throws Throwable {
125124
return returnedObject;
126125
}
127126
MethodSecurityExpressionHandler expressionHandler = this.registry.getExpressionHandler();
128-
EvaluationContext ctx = expressionHandler.createEvaluationContext(this.authentication, mi);
127+
EvaluationContext ctx = expressionHandler.createEvaluationContext(this::getAuthentication, mi);
129128
return expressionHandler.filter(returnedObject, attribute.getExpression(), ctx);
130129
}
131130

132-
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
133-
return () -> {
134-
Authentication authentication = strategy.getContext().getAuthentication();
135-
if (authentication == null) {
136-
throw new AuthenticationCredentialsNotFoundException(
137-
"An Authentication object was not found in the SecurityContext");
138-
}
139-
return authentication;
140-
};
131+
private Authentication getAuthentication() {
132+
Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
133+
if (authentication == null) {
134+
throw new AuthenticationCredentialsNotFoundException(
135+
"An Authentication object was not found in the SecurityContext");
136+
}
137+
return authentication;
141138
}
142139

143140
}

core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -47,8 +47,7 @@
4747
public final class PreFilterAuthorizationMethodInterceptor
4848
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
4949

50-
private Supplier<Authentication> authentication = getAuthentication(
51-
SecurityContextHolder.getContextHolderStrategy());
50+
private Supplier<SecurityContextHolderStrategy> securityContextHolderStrategy = SecurityContextHolder::getContextHolderStrategy;
5251

5352
private PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
5453

@@ -109,7 +108,7 @@ public boolean isPerInstance() {
109108
* @since 5.8
110109
*/
111110
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
112-
this.authentication = getAuthentication(strategy);
111+
this.securityContextHolderStrategy = () -> strategy;
113112
}
114113

115114
/**
@@ -124,7 +123,7 @@ public Object invoke(MethodInvocation mi) throws Throwable {
124123
return mi.proceed();
125124
}
126125
MethodSecurityExpressionHandler expressionHandler = this.registry.getExpressionHandler();
127-
EvaluationContext ctx = expressionHandler.createEvaluationContext(this.authentication, mi);
126+
EvaluationContext ctx = expressionHandler.createEvaluationContext(this::getAuthentication, mi);
128127
Object filterTarget = findFilterTarget(attribute.getFilterTarget(), ctx, mi);
129128
expressionHandler.filter(filterTarget, attribute.getExpression(), ctx);
130129
return mi.proceed();
@@ -150,15 +149,13 @@ private Object findFilterTarget(String filterTargetName, EvaluationContext ctx,
150149
return filterTarget;
151150
}
152151

153-
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
154-
return () -> {
155-
Authentication authentication = strategy.getContext().getAuthentication();
156-
if (authentication == null) {
157-
throw new AuthenticationCredentialsNotFoundException(
158-
"An Authentication object was not found in the SecurityContext");
159-
}
160-
return authentication;
161-
};
152+
private Authentication getAuthentication() {
153+
Authentication authentication = this.securityContextHolderStrategy.get().getContext().getAuthentication();
154+
if (authentication == null) {
155+
throw new AuthenticationCredentialsNotFoundException(
156+
"An Authentication object was not found in the SecurityContext");
157+
}
158+
return authentication;
162159
}
163160

164161
}

core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
2929
import org.springframework.security.authorization.AuthorizationEventPublisher;
3030
import org.springframework.security.authorization.AuthorizationManager;
3131
import org.springframework.security.core.Authentication;
32+
import org.springframework.security.core.authority.AuthorityUtils;
3233
import org.springframework.security.core.context.SecurityContext;
3334
import org.springframework.security.core.context.SecurityContextHolder;
3435
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -91,6 +92,25 @@ public void afterWhenMockSecurityContextHolderStrategyThenUses() throws Throwabl
9192
verify(strategy).getContext();
9293
}
9394

95+
// gh-12877
96+
@Test
97+
public void afterWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
98+
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
99+
Authentication authentication = new TestingAuthenticationToken("john", "password",
100+
AuthorityUtils.createAuthorityList("authority"));
101+
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
102+
MethodInvocation invocation = mock(MethodInvocation.class);
103+
AuthorizationManager<MethodInvocationResult> authorizationManager = AuthenticatedAuthorizationManager
104+
.authenticated();
105+
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
106+
Pointcut.TRUE, authorizationManager);
107+
SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
108+
SecurityContextHolder.setContextHolderStrategy(strategy);
109+
advice.invoke(invocation);
110+
verify(strategy).getContext();
111+
SecurityContextHolder.setContextHolderStrategy(saved);
112+
}
113+
94114
@Test
95115
public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
96116
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(

core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -87,6 +87,24 @@ public void beforeWhenMockSecurityContextHolderStrategyThenUses() throws Throwab
8787
verify(strategy).getContext();
8888
}
8989

90+
// gh-12877
91+
@Test
92+
public void beforeWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
93+
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
94+
Authentication authentication = new TestingAuthenticationToken("john", "password",
95+
AuthorityUtils.createAuthorityList("authority"));
96+
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
97+
MethodInvocation invocation = mock(MethodInvocation.class);
98+
AuthorizationManager<MethodInvocation> authorizationManager = AuthenticatedAuthorizationManager.authenticated();
99+
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
100+
Pointcut.TRUE, authorizationManager);
101+
SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
102+
SecurityContextHolder.setContextHolderStrategy(strategy);
103+
advice.invoke(invocation);
104+
verify(strategy).getContext();
105+
SecurityContextHolder.setContextHolderStrategy(saved);
106+
}
107+
90108
@Test
91109
public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
92110
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(

core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptorTests.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -147,6 +147,29 @@ public Object proceed() {
147147
verify(strategy).getContext();
148148
}
149149

150+
// gh-12877
151+
@Test
152+
public void postFilterWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
153+
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
154+
Authentication authentication = new TestingAuthenticationToken("john", "password",
155+
AuthorityUtils.createAuthorityList("authority"));
156+
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
157+
String[] array = { "john", "bob" };
158+
MockMethodInvocation invocation = new MockMethodInvocation(new TestClass(), TestClass.class,
159+
"doSomethingArrayAuthentication", new Class[] { String[].class }, new Object[] { array }) {
160+
@Override
161+
public Object proceed() {
162+
return array;
163+
}
164+
};
165+
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
166+
SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
167+
SecurityContextHolder.setContextHolderStrategy(strategy);
168+
advice.invoke(invocation);
169+
verify(strategy).getContext();
170+
SecurityContextHolder.setContextHolderStrategy(saved);
171+
}
172+
150173
@PostFilter("filterObject == 'john'")
151174
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
152175

core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptorTests.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -204,6 +204,26 @@ public void preFilterWhenMockSecurityContextHolderStrategyThenUses() throws Thro
204204
verify(strategy).getContext();
205205
}
206206

207+
// gh-12877
208+
@Test
209+
public void preFilterWhenStaticSecurityContextHolderStrategyAfterConstructorThenUses() throws Throwable {
210+
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
211+
Authentication authentication = new TestingAuthenticationToken("john", "password",
212+
AuthorityUtils.createAuthorityList("authority"));
213+
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
214+
List<String> list = new ArrayList<>();
215+
list.add("john");
216+
list.add("bob");
217+
MockMethodInvocation invocation = new MockMethodInvocation(new TestClass(), TestClass.class,
218+
"doSomethingArrayFilterAuthentication", new Class[] { List.class }, new Object[] { list });
219+
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
220+
SecurityContextHolderStrategy saved = SecurityContextHolder.getContextHolderStrategy();
221+
SecurityContextHolder.setContextHolderStrategy(strategy);
222+
advice.invoke(invocation);
223+
verify(strategy).getContext();
224+
SecurityContextHolder.setContextHolderStrategy(saved);
225+
}
226+
207227
@PreFilter("filterObject == 'john'")
208228
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
209229

0 commit comments

Comments
 (0)