Skip to content

Commit f43dce3

Browse files
committed
Merge branch '1.3.x' into 1.4.x
2 parents 7870f47 + c624d0a commit f43dce3

File tree

3 files changed

+34
-62
lines changed

3 files changed

+34
-62
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilter.java

+15-45
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2025 the original author or authors.
2+
* Copyright 2020-2024 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.
@@ -34,7 +34,6 @@
3434
import org.springframework.security.core.AuthenticationException;
3535
import org.springframework.security.core.context.SecurityContext;
3636
import org.springframework.security.core.context.SecurityContextHolder;
37-
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
3837
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
3938
import org.springframework.security.oauth2.core.OAuth2Error;
4039
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
@@ -54,7 +53,6 @@
5453
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
5554
import org.springframework.security.web.authentication.DelegatingAuthenticationConverter;
5655
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
57-
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
5856
import org.springframework.security.web.util.matcher.RequestMatcher;
5957
import org.springframework.util.Assert;
6058
import org.springframework.web.filter.OncePerRequestFilter;
@@ -92,8 +90,6 @@ public final class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter
9290

9391
private final AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
9492

95-
private final BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
96-
9793
private AuthenticationConverter authenticationConverter;
9894

9995
private AuthenticationSuccessHandler authenticationSuccessHandler = this::onAuthenticationSuccess;
@@ -114,7 +110,6 @@ public OAuth2ClientAuthenticationFilter(AuthenticationManager authenticationMana
114110
Assert.notNull(requestMatcher, "requestMatcher cannot be null");
115111
this.authenticationManager = authenticationManager;
116112
this.requestMatcher = requestMatcher;
117-
this.basicAuthenticationEntryPoint.setRealmName("default");
118113
// @formatter:off
119114
this.authenticationConverter = new DelegatingAuthenticationConverter(
120115
Arrays.asList(
@@ -135,9 +130,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
135130
return;
136131
}
137132

138-
Authentication authenticationRequest = null;
139133
try {
140-
authenticationRequest = this.authenticationConverter.convert(request);
134+
Authentication authenticationRequest = this.authenticationConverter.convert(request);
141135
if (authenticationRequest instanceof AbstractAuthenticationToken) {
142136
((AbstractAuthenticationToken) authenticationRequest)
143137
.setDetails(this.authenticationDetailsSource.buildDetails(request));
@@ -154,14 +148,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
154148
if (this.logger.isTraceEnabled()) {
155149
this.logger.trace(LogMessage.format("Client authentication failed: %s", ex.getError()), ex);
156150
}
157-
if (authenticationRequest instanceof OAuth2ClientAuthenticationToken clientAuthentication) {
158-
this.authenticationFailureHandler.onAuthenticationFailure(request, response,
159-
new OAuth2ClientAuthenticationException(ex.getError(), ex, clientAuthentication));
160-
}
161-
else {
162-
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
163-
}
164-
151+
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
165152
}
166153
}
167154

@@ -213,21 +200,21 @@ private void onAuthenticationSuccess(HttpServletRequest request, HttpServletResp
213200
}
214201

215202
private void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
216-
AuthenticationException authenticationException) throws IOException {
203+
AuthenticationException exception) throws IOException {
217204

218205
SecurityContextHolder.clearContext();
219206

220-
if (authenticationException instanceof OAuth2ClientAuthenticationException clientAuthenticationException) {
221-
OAuth2ClientAuthenticationToken clientAuthentication = clientAuthenticationException
222-
.getClientAuthentication();
223-
if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC
224-
.equals(clientAuthentication.getClientAuthenticationMethod())) {
225-
this.basicAuthenticationEntryPoint.commence(request, response, authenticationException);
226-
return;
227-
}
228-
}
229-
230-
OAuth2Error error = ((OAuth2AuthenticationException) authenticationException).getError();
207+
// TODO
208+
// The authorization server MAY return an HTTP 401 (Unauthorized) status code
209+
// to indicate which HTTP authentication schemes are supported.
210+
// If the client attempted to authenticate via the "Authorization" request header
211+
// field,
212+
// the authorization server MUST respond with an HTTP 401 (Unauthorized) status
213+
// code and
214+
// include the "WWW-Authenticate" response header field
215+
// matching the authentication scheme used by the client.
216+
217+
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
231218
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
232219
if (OAuth2ErrorCodes.INVALID_CLIENT.equals(error.getErrorCode())) {
233220
httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
@@ -262,21 +249,4 @@ private static void validateClientIdentifier(Authentication authentication) {
262249
}
263250
}
264251

265-
private static final class OAuth2ClientAuthenticationException extends OAuth2AuthenticationException {
266-
267-
private final OAuth2ClientAuthenticationToken clientAuthentication;
268-
269-
private OAuth2ClientAuthenticationException(OAuth2Error error, Throwable cause,
270-
OAuth2ClientAuthenticationToken clientAuthentication) {
271-
super(error, cause);
272-
Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
273-
this.clientAuthentication = clientAuthentication;
274-
}
275-
276-
private OAuth2ClientAuthenticationToken getClientAuthentication() {
277-
return this.clientAuthentication;
278-
}
279-
280-
}
281-
282252
}

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2025 the original author or authors.
2+
* Copyright 2020-2024 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.
@@ -538,7 +538,7 @@ public void requestWhenPublicClientWithPkceAndEmptyCodeThenBadRequest() throws E
538538
}
539539

540540
@Test
541-
public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenUnauthorized() throws Exception {
541+
public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenBadRequest() throws Exception {
542542
this.spring.register(AuthorizationServerConfiguration.class).autowire();
543543

544544
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
@@ -569,7 +569,7 @@ public void requestWhenConfidentialClientWithPkceAndMissingCodeVerifierThenUnaut
569569
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
570570
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
571571
.header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(registeredClient)))
572-
.andExpect(status().isUnauthorized());
572+
.andExpect(status().isBadRequest());
573573
}
574574

575575
// gh-1011
@@ -601,7 +601,7 @@ public void requestWhenConfidentialClientWithPkceAndMissingCodeChallengeThenErro
601601
}
602602

603603
@Test
604-
public void requestWhenConfidentialClientWithPkceAndMissingCodeChallengeButCodeVerifierProvidedThenUnauthorized()
604+
public void requestWhenConfidentialClientWithPkceAndMissingCodeChallengeButCodeVerifierProvidedThenBadRequest()
605605
throws Exception {
606606
this.spring.register(AuthorizationServerConfiguration.class).autowire();
607607

@@ -631,7 +631,7 @@ public void requestWhenConfidentialClientWithPkceAndMissingCodeChallengeButCodeV
631631
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
632632
.param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER)
633633
.header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(registeredClient)))
634-
.andExpect(status().isUnauthorized());
634+
.andExpect(status().isBadRequest());
635635
}
636636

637637
@Test

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2025 the original author or authors.
2+
* Copyright 2020-2022 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.
@@ -26,7 +26,6 @@
2626
import org.junit.jupiter.api.Test;
2727
import org.mockito.ArgumentCaptor;
2828

29-
import org.springframework.http.HttpHeaders;
3029
import org.springframework.http.HttpMethod;
3130
import org.springframework.http.HttpStatus;
3231
import org.springframework.http.converter.HttpMessageConverter;
@@ -176,25 +175,26 @@ public void doFilterWhenRequestMatchesAndInvalidCredentialsThenInvalidRequestErr
176175

177176
// gh-889
178177
@Test
179-
public void doFilterWhenRequestMatchesAndClientIdContainsNonPrintableASCIIThenReturnChallenge() throws Exception {
178+
public void doFilterWhenRequestMatchesAndClientIdContainsNonPrintableASCIIThenInvalidRequestError()
179+
throws Exception {
180180
// Hex 00 -> null
181181
String clientId = new String(Hex.decode("00"), StandardCharsets.UTF_8);
182-
assertWhenInvalidClientIdThenReturnChallenge(clientId);
182+
assertWhenInvalidClientIdThenInvalidRequestError(clientId);
183183

184184
// Hex 0a61 -> line feed + a
185185
clientId = new String(Hex.decode("0a61"), StandardCharsets.UTF_8);
186-
assertWhenInvalidClientIdThenReturnChallenge(clientId);
186+
assertWhenInvalidClientIdThenInvalidRequestError(clientId);
187187

188188
// Hex 1b -> escape
189189
clientId = new String(Hex.decode("1b"), StandardCharsets.UTF_8);
190-
assertWhenInvalidClientIdThenReturnChallenge(clientId);
190+
assertWhenInvalidClientIdThenInvalidRequestError(clientId);
191191

192192
// Hex 1b61 -> escape + a
193193
clientId = new String(Hex.decode("1b61"), StandardCharsets.UTF_8);
194-
assertWhenInvalidClientIdThenReturnChallenge(clientId);
194+
assertWhenInvalidClientIdThenInvalidRequestError(clientId);
195195
}
196196

197-
private void assertWhenInvalidClientIdThenReturnChallenge(String clientId) throws Exception {
197+
private void assertWhenInvalidClientIdThenInvalidRequestError(String clientId) throws Exception {
198198
given(this.authenticationConverter.convert(any(HttpServletRequest.class)))
199199
.willReturn(new OAuth2ClientAuthenticationToken(clientId, ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
200200
"secret", null));
@@ -210,12 +210,13 @@ private void assertWhenInvalidClientIdThenReturnChallenge(String clientId) throw
210210
verifyNoInteractions(this.authenticationManager);
211211

212212
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
213-
assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
214-
assertThat(response.getHeader(HttpHeaders.WWW_AUTHENTICATE)).isEqualTo("Basic realm=\"default\"");
213+
assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
214+
OAuth2Error error = readError(response);
215+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
215216
}
216217

217218
@Test
218-
public void doFilterWhenRequestMatchesAndBadCredentialsThenReturnChallenge() throws Exception {
219+
public void doFilterWhenRequestMatchesAndBadCredentialsThenInvalidClientError() throws Exception {
219220
given(this.authenticationConverter.convert(any(HttpServletRequest.class)))
220221
.willReturn(new OAuth2ClientAuthenticationToken("clientId", ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
221222
"invalid-secret", null));
@@ -234,7 +235,8 @@ public void doFilterWhenRequestMatchesAndBadCredentialsThenReturnChallenge() thr
234235

235236
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
236237
assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
237-
assertThat(response.getHeader(HttpHeaders.WWW_AUTHENTICATE)).isEqualTo("Basic realm=\"default\"");
238+
OAuth2Error error = readError(response);
239+
assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
238240
}
239241

240242
@Test

0 commit comments

Comments
 (0)