Skip to content

Commit c4406cd

Browse files
committed
Remove temporary HttpSessionSecurityContextRepository
Issue gh-482
1 parent d8421d5 commit c4406cd

File tree

3 files changed

+14
-148
lines changed

3 files changed

+14
-148
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerConfigurer.java

Lines changed: 0 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,17 @@
1616
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
1717

1818
import java.net.URI;
19-
import java.util.ArrayList;
2019
import java.util.LinkedHashMap;
21-
import java.util.List;
2220
import java.util.Map;
2321

24-
import javax.servlet.AsyncContext;
25-
import javax.servlet.ServletRequest;
26-
import javax.servlet.ServletResponse;
27-
import javax.servlet.http.HttpServletRequest;
28-
import javax.servlet.http.HttpServletRequestWrapper;
29-
import javax.servlet.http.HttpServletResponse;
30-
3122
import com.nimbusds.jose.jwk.source.JWKSource;
3223

33-
import org.springframework.core.annotation.AnnotationUtils;
3424
import org.springframework.http.HttpMethod;
3525
import org.springframework.http.HttpStatus;
3626
import org.springframework.security.config.Customizer;
3727
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
3828
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
3929
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
40-
import org.springframework.security.core.Authentication;
41-
import org.springframework.security.core.Transient;
42-
import org.springframework.security.core.context.SecurityContext;
4330
import org.springframework.security.oauth2.core.OAuth2Token;
4431
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
4532
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
@@ -51,11 +38,7 @@
5138
import org.springframework.security.oauth2.server.authorization.web.ProviderContextFilter;
5239
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
5340
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
54-
import org.springframework.security.web.context.HttpRequestResponseHolder;
55-
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
56-
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
5741
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
58-
import org.springframework.security.web.context.SecurityContextRepository;
5942
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
6043
import org.springframework.security.web.util.matcher.OrRequestMatcher;
6144
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -254,127 +237,6 @@ public void init(B builder) {
254237
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class))
255238
);
256239
}
257-
258-
// gh-482
259-
initSecurityContextRepository(builder);
260-
}
261-
262-
private void initSecurityContextRepository(B builder) {
263-
// TODO This is a temporary fix and should be removed after upgrading to Spring Security 5.7.0 GA.
264-
//
265-
// See:
266-
// Prevent Save @Transient Authentication with existing HttpSession
267-
// https://github.com/spring-projects/spring-security/pull/9993
268-
269-
final SecurityContextRepository securityContextRepository = builder.getSharedObject(SecurityContextRepository.class);
270-
if (!(securityContextRepository instanceof HttpSessionSecurityContextRepository)) {
271-
return;
272-
}
273-
274-
SecurityContextRepository securityContextRepositoryTransientNotSaved = new SecurityContextRepository() {
275-
276-
private final RequestMatcher clientAuthenticationRequestMatcher = initClientAuthenticationRequestMatcher();
277-
private final RequestMatcher jwtAuthenticationRequestMatcher = initJwtAuthenticationRequestMatcher();
278-
279-
@Override
280-
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
281-
final HttpServletRequest unwrappedRequest = requestResponseHolder.getRequest();
282-
final HttpServletResponse unwrappedResponse = requestResponseHolder.getResponse();
283-
284-
SecurityContext securityContext = securityContextRepository.loadContext(requestResponseHolder);
285-
286-
if (this.clientAuthenticationRequestMatcher.matches(unwrappedRequest) ||
287-
this.jwtAuthenticationRequestMatcher.matches(unwrappedRequest)) {
288-
289-
final SaveContextOnUpdateOrErrorResponseWrapper transientAuthenticationResponseWrapper =
290-
new SaveContextOnUpdateOrErrorResponseWrapper(unwrappedResponse, false) {
291-
292-
@Override
293-
protected void saveContext(SecurityContext context) {
294-
// @Transient Authentication should not be saved
295-
if (context.getAuthentication() != null) {
296-
Assert.state(isTransientAuthentication(context.getAuthentication()), "Expected @Transient Authentication");
297-
}
298-
}
299-
300-
};
301-
// Override the default HttpSessionSecurityContextRepository.SaveToSessionResponseWrapper
302-
requestResponseHolder.setResponse(transientAuthenticationResponseWrapper);
303-
304-
final HttpServletRequestWrapper transientAuthenticationRequestWrapper =
305-
new HttpServletRequestWrapper(unwrappedRequest) {
306-
307-
@Override
308-
public AsyncContext startAsync() {
309-
transientAuthenticationResponseWrapper.disableSaveOnResponseCommitted();
310-
return super.startAsync();
311-
}
312-
313-
@Override
314-
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
315-
throws IllegalStateException {
316-
transientAuthenticationResponseWrapper.disableSaveOnResponseCommitted();
317-
return super.startAsync(servletRequest, servletResponse);
318-
}
319-
320-
};
321-
// Override the default HttpSessionSecurityContextRepository.SaveToSessionRequestWrapper
322-
requestResponseHolder.setRequest(transientAuthenticationRequestWrapper);
323-
}
324-
325-
return securityContext;
326-
}
327-
328-
@Override
329-
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
330-
Authentication authentication = context.getAuthentication();
331-
if (authentication == null || isTransientAuthentication(authentication)) {
332-
return;
333-
}
334-
securityContextRepository.saveContext(context, request, response);
335-
}
336-
337-
@Override
338-
public boolean containsContext(HttpServletRequest request) {
339-
return securityContextRepository.containsContext(request);
340-
}
341-
342-
private boolean isTransientAuthentication(Authentication authentication) {
343-
return AnnotationUtils.getAnnotation(authentication.getClass(), Transient.class) != null;
344-
}
345-
346-
private RequestMatcher initClientAuthenticationRequestMatcher() {
347-
// OAuth2ClientAuthenticationToken is @Transient and is accepted by
348-
// OAuth2TokenEndpointFilter, OAuth2TokenIntrospectionEndpointFilter and OAuth2TokenRevocationEndpointFilter
349-
350-
List<RequestMatcher> requestMatchers = new ArrayList<>();
351-
requestMatchers.add(getRequestMatcher(OAuth2TokenEndpointConfigurer.class));
352-
requestMatchers.add(getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class));
353-
requestMatchers.add(getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class));
354-
return new OrRequestMatcher(requestMatchers);
355-
}
356-
357-
private RequestMatcher initJwtAuthenticationRequestMatcher() {
358-
// JwtAuthenticationToken is @Transient and is accepted by
359-
// OidcUserInfoEndpointFilter and OidcClientRegistrationEndpointFilter
360-
361-
List<RequestMatcher> requestMatchers = new ArrayList<>();
362-
requestMatchers.add(
363-
getConfigurer(OidcConfigurer.class)
364-
.getConfigurer(OidcUserInfoEndpointConfigurer.class).getRequestMatcher()
365-
);
366-
OidcClientRegistrationEndpointConfigurer clientRegistrationEndpointConfigurer =
367-
getConfigurer(OidcConfigurer.class)
368-
.getConfigurer(OidcClientRegistrationEndpointConfigurer.class);
369-
if (clientRegistrationEndpointConfigurer != null) {
370-
requestMatchers.add(clientRegistrationEndpointConfigurer.getRequestMatcher());
371-
}
372-
return new OrRequestMatcher(requestMatchers);
373-
}
374-
375-
};
376-
377-
builder.setSharedObject(SecurityContextRepository.class, securityContextRepositoryTransientNotSaved);
378240
}
379241

380242
@Override

oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@
127127
import static org.mockito.ArgumentMatchers.any;
128128
import static org.mockito.ArgumentMatchers.eq;
129129
import static org.mockito.Mockito.mock;
130-
import static org.mockito.Mockito.never;
131130
import static org.mockito.Mockito.reset;
132131
import static org.mockito.Mockito.spy;
133132
import static org.mockito.Mockito.times;
@@ -669,7 +668,7 @@ public void requestWhenClientObtainsAccessTokenThenClientAuthenticationNotPersis
669668
String authorizationCode = extractParameterFromRedirectUri(mvcResult.getResponse().getRedirectedUrl(), "code");
670669
OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
671670

672-
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
671+
mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
673672
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
674673
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
675674
.param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER))
@@ -680,9 +679,12 @@ public void requestWhenClientObtainsAccessTokenThenClientAuthenticationNotPersis
680679
.andExpect(jsonPath("$.token_type").isNotEmpty())
681680
.andExpect(jsonPath("$.expires_in").isNotEmpty())
682681
.andExpect(jsonPath("$.refresh_token").doesNotExist())
683-
.andExpect(jsonPath("$.scope").isNotEmpty());
682+
.andExpect(jsonPath("$.scope").isNotEmpty())
683+
.andReturn();
684684

685-
verify(securityContextRepository, never()).saveContext(any(), any(), any());
685+
org.springframework.security.core.context.SecurityContext securityContext =
686+
securityContextRepository.loadContext(mvcResult.getRequest()).get();
687+
assertThat(securityContext.getAuthentication()).isNull();
686688
}
687689

688690
private static MultiValueMap<String, String> getAuthorizationRequestParameters(RegisteredClient registeredClient) {

oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcUserInfoTests.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,12 @@
6969
import org.springframework.security.web.context.SecurityContextRepository;
7070
import org.springframework.security.web.util.matcher.RequestMatcher;
7171
import org.springframework.test.web.servlet.MockMvc;
72+
import org.springframework.test.web.servlet.MvcResult;
7273
import org.springframework.test.web.servlet.ResultMatcher;
7374

74-
import static org.mockito.ArgumentMatchers.any;
75-
import static org.mockito.Mockito.never;
75+
import static org.assertj.core.api.Assertions.assertThat;
7676
import static org.mockito.Mockito.reset;
7777
import static org.mockito.Mockito.spy;
78-
import static org.mockito.Mockito.verify;
7978
import static org.springframework.test.web.servlet.ResultMatcher.matchAll;
8079
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
8180
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -171,13 +170,16 @@ public void requestWhenUserInfoRequestThenBearerTokenAuthenticationNotPersisted(
171170

172171
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
173172
// @formatter:off
174-
this.mvc.perform(get(DEFAULT_OIDC_USER_INFO_ENDPOINT_URI)
173+
MvcResult mvcResult = this.mvc.perform(get(DEFAULT_OIDC_USER_INFO_ENDPOINT_URI)
175174
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken.getTokenValue()))
176175
.andExpect(status().is2xxSuccessful())
177-
.andExpect(userInfoResponse());
176+
.andExpect(userInfoResponse())
177+
.andReturn();
178178
// @formatter:on
179179

180-
verify(securityContextRepository, never()).saveContext(any(), any(), any());
180+
org.springframework.security.core.context.SecurityContext securityContext =
181+
securityContextRepository.loadContext(mvcResult.getRequest()).get();
182+
assertThat(securityContext.getAuthentication()).isNull();
181183
}
182184

183185
private static ResultMatcher userInfoResponse() {

0 commit comments

Comments
 (0)