Skip to content

Commit 5086409

Browse files
committed
Use SecurityContextHolderStrategy for Digest
Issue gh-11060
1 parent 44d99f4 commit 5086409

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed

web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.springframework.security.core.SpringSecurityMessageSource;
4343
import org.springframework.security.core.context.SecurityContext;
4444
import org.springframework.security.core.context.SecurityContextHolder;
45+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
4546
import org.springframework.security.core.userdetails.UserCache;
4647
import org.springframework.security.core.userdetails.UserDetails;
4748
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -93,6 +94,9 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
9394

9495
private static final Log logger = LogFactory.getLog(DigestAuthenticationFilter.class);
9596

97+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
98+
.getContextHolderStrategy();
99+
96100
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
97101

98102
private DigestAuthenticationEntryPoint authenticationEntryPoint;
@@ -192,9 +196,9 @@ private void doFilter(HttpServletRequest request, HttpServletResponse response,
192196
logger.debug(LogMessage.format("Authentication success for user: '%s' with response: '%s'",
193197
digestAuth.getUsername(), digestAuth.getResponse()));
194198
Authentication authentication = createSuccessfulAuthentication(request, user);
195-
SecurityContext context = SecurityContextHolder.createEmptyContext();
199+
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
196200
context.setAuthentication(authentication);
197-
SecurityContextHolder.setContext(context);
201+
this.securityContextHolderStrategy.setContext(context);
198202
this.securityContextRepository.saveContext(context, request, response);
199203
chain.doFilter(request, response);
200204
}
@@ -214,8 +218,8 @@ private UsernamePasswordAuthenticationToken getAuthRequest(UserDetails user) {
214218

215219
private void fail(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
216220
throws IOException, ServletException {
217-
SecurityContext context = SecurityContextHolder.createEmptyContext();
218-
SecurityContextHolder.setContext(context);
221+
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
222+
this.securityContextHolderStrategy.setContext(context);
219223
logger.debug(failed);
220224
this.authenticationEntryPoint.commence(request, response, failed);
221225
}
@@ -287,6 +291,17 @@ public void setSecurityContextRepository(SecurityContextRepository securityConte
287291
this.securityContextRepository = securityContextRepository;
288292
}
289293

294+
/**
295+
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
296+
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
297+
*
298+
* @since 5.8
299+
*/
300+
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
301+
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
302+
this.securityContextHolderStrategy = securityContextHolderStrategy;
303+
}
304+
290305
private class DigestData {
291306

292307
private final String username;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security;
18+
19+
import org.springframework.security.core.context.SecurityContext;
20+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
21+
import org.springframework.security.core.context.SecurityContextImpl;
22+
23+
public class MockSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
24+
25+
private SecurityContext mock;
26+
27+
@Override
28+
public void clearContext() {
29+
this.mock = null;
30+
}
31+
32+
@Override
33+
public SecurityContext getContext() {
34+
return this.mock;
35+
}
36+
37+
@Override
38+
public void setContext(SecurityContext context) {
39+
this.mock = context;
40+
}
41+
42+
@Override
43+
public SecurityContext createEmptyContext() {
44+
return new SecurityContextImpl();
45+
}
46+
47+
}

web/src/test/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilterTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030

3131
import org.springframework.mock.web.MockHttpServletRequest;
3232
import org.springframework.mock.web.MockHttpServletResponse;
33+
import org.springframework.security.MockSecurityContextHolderStrategy;
3334
import org.springframework.security.authentication.TestingAuthenticationToken;
3435
import org.springframework.security.core.authority.AuthorityUtils;
3536
import org.springframework.security.core.context.SecurityContext;
3637
import org.springframework.security.core.context.SecurityContextHolder;
38+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
3739
import org.springframework.security.core.userdetails.User;
3840
import org.springframework.security.core.userdetails.UserDetails;
3941
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -44,8 +46,10 @@
4446

4547
import static org.assertj.core.api.Assertions.assertThat;
4648
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
49+
import static org.mockito.ArgumentMatchers.any;
4750
import static org.mockito.ArgumentMatchers.eq;
4851
import static org.mockito.Mockito.mock;
52+
import static org.mockito.Mockito.spy;
4953
import static org.mockito.Mockito.times;
5054
import static org.mockito.Mockito.verify;
5155

@@ -306,6 +310,18 @@ public void startupDetectsMissingUserDetailsService() {
306310
assertThatIllegalArgumentException().isThrownBy(filter::afterPropertiesSet);
307311
}
308312

313+
@Test
314+
public void authenticateUsesCustomSecurityContextHolderStrategy() throws Exception {
315+
SecurityContextHolderStrategy securityContextHolderStrategy = spy(new MockSecurityContextHolderStrategy());
316+
String responseDigest = DigestAuthUtils.generateDigest(false, USERNAME, REALM, PASSWORD, "GET", REQUEST_URI,
317+
QOP, NONCE, NC, CNONCE);
318+
this.request.addHeader("Authorization",
319+
createAuthorizationHeader(USERNAME, REALM, NONCE, REQUEST_URI, responseDigest, QOP, NC, CNONCE));
320+
this.filter.setSecurityContextHolderStrategy(securityContextHolderStrategy);
321+
executeFilterInContainerSimulator(this.filter, this.request, true);
322+
verify(securityContextHolderStrategy).setContext(any());
323+
}
324+
309325
@Test
310326
public void successfulLoginThenFailedLoginResultsInSessionLosingToken() throws Exception {
311327
String responseDigest = DigestAuthUtils.generateDigest(false, USERNAME, REALM, PASSWORD, "GET", REQUEST_URI,

0 commit comments

Comments
 (0)