diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationException.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationException.java
new file mode 100644
index 000000000..a4a67f1f4
--- /dev/null
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationException.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020-2025 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.oauth2.server.authorization.authentication;
+
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.util.Assert;
+
+/**
+ * An {@link OAuth2AuthenticationException} that holds an
+ * {@link OAuth2ClientAuthenticationToken} and is used by an
+ * {@code AuthenticationFailureHandler} when handling a failed authentication attempt by
+ * an OAuth 2.0 Client.
+ *
+ * @author Joe Grandja
+ * @since 1.5
+ * @see OAuth2ClientAuthenticationToken
+ */
+public class OAuth2ClientAuthenticationException extends OAuth2AuthenticationException {
+
+ private final OAuth2ClientAuthenticationToken clientAuthentication;
+
+ /**
+ * Constructs an {@code OAuth2ClientAuthenticationException} using the provided
+ * parameters.
+ * @param error the {@link OAuth2Error OAuth 2.0 Error}
+ * @param clientAuthentication the {@link OAuth2ClientAuthenticationToken OAuth 2.0
+ * Client Authentication} request
+ */
+ public OAuth2ClientAuthenticationException(OAuth2Error error,
+ OAuth2ClientAuthenticationToken clientAuthentication) {
+ super(error);
+ Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
+ this.clientAuthentication = clientAuthentication;
+ }
+
+ /**
+ * Constructs an {@code OAuth2ClientAuthenticationException} using the provided
+ * parameters.
+ * @param error the {@link OAuth2Error OAuth 2.0 Error}
+ * @param cause the root cause
+ * @param clientAuthentication the {@link OAuth2ClientAuthenticationToken OAuth 2.0
+ * Client Authentication} request
+ */
+ public OAuth2ClientAuthenticationException(OAuth2Error error, Throwable cause,
+ OAuth2ClientAuthenticationToken clientAuthentication) {
+ super(error, cause);
+ Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
+ this.clientAuthentication = clientAuthentication;
+ }
+
+ /**
+ * Returns the {@link OAuth2ClientAuthenticationToken OAuth 2.0 Client Authentication}
+ * request.
+ * @return the {@link OAuth2ClientAuthenticationToken}
+ */
+ public OAuth2ClientAuthenticationToken getClientAuthentication() {
+ return this.clientAuthentication;
+ }
+
+}
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilter.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilter.java
index f25cca050..58af4937e 100644
--- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilter.java
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilter.java
@@ -24,29 +24,25 @@
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.log.LogMessage;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
-import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
import org.springframework.security.oauth2.server.authorization.authentication.ClientSecretAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.JwtClientAssertionAuthenticationProvider;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationException;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.PublicClientAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.X509ClientCertificateAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.web.authentication.ClientSecretBasicAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.ClientSecretPostAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.JwtClientAssertionAuthenticationConverter;
+import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2ClientAuthenticationFailureHandler;
import org.springframework.security.oauth2.server.authorization.web.authentication.PublicClientAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.X509ClientCertificateAuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationConverter;
@@ -54,7 +50,6 @@
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.DelegatingAuthenticationConverter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
-import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -75,6 +70,7 @@
* @see ClientSecretAuthenticationProvider
* @see PublicClientAuthenticationConverter
* @see PublicClientAuthenticationProvider
+ * @see OAuth2ClientAuthenticationFailureHandler
* @see Section 2.3 Client
* Authentication
@@ -88,17 +84,13 @@ public final class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter
private final RequestMatcher requestMatcher;
- private final HttpMessageConverter errorHttpResponseConverter = new OAuth2ErrorHttpMessageConverter();
-
private final AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
- private final BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
-
private AuthenticationConverter authenticationConverter;
private AuthenticationSuccessHandler authenticationSuccessHandler = this::onAuthenticationSuccess;
- private AuthenticationFailureHandler authenticationFailureHandler = this::onAuthenticationFailure;
+ private AuthenticationFailureHandler authenticationFailureHandler = new OAuth2ClientAuthenticationFailureHandler();
/**
* Constructs an {@code OAuth2ClientAuthenticationFilter} using the provided
@@ -114,7 +106,6 @@ public OAuth2ClientAuthenticationFilter(AuthenticationManager authenticationMana
Assert.notNull(requestMatcher, "requestMatcher cannot be null");
this.authenticationManager = authenticationManager;
this.requestMatcher = requestMatcher;
- this.basicAuthenticationEntryPoint.setRealmName("default");
// @formatter:off
this.authenticationConverter = new DelegatingAuthenticationConverter(
Arrays.asList(
@@ -138,16 +129,16 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
Authentication authenticationRequest = null;
try {
authenticationRequest = this.authenticationConverter.convert(request);
+ if (authenticationRequest == null) {
+ throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
+ }
if (authenticationRequest instanceof AbstractAuthenticationToken authenticationToken) {
authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
- if (authenticationRequest != null) {
- validateClientIdentifier(authenticationRequest);
- Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
- this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
- }
+ validateClientIdentifier(authenticationRequest);
+ Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
+ this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
filterChain.doFilter(request, response);
-
}
catch (OAuth2AuthenticationException ex) {
if (this.logger.isTraceEnabled()) {
@@ -160,8 +151,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
else {
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
}
-
}
+
}
/**
@@ -211,35 +202,6 @@ private void onAuthenticationSuccess(HttpServletRequest request, HttpServletResp
}
}
- private void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
- AuthenticationException authenticationException) throws IOException {
-
- SecurityContextHolder.clearContext();
-
- if (authenticationException instanceof OAuth2ClientAuthenticationException clientAuthenticationException) {
- OAuth2ClientAuthenticationToken clientAuthentication = clientAuthenticationException
- .getClientAuthentication();
- if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC
- .equals(clientAuthentication.getClientAuthenticationMethod())) {
- this.basicAuthenticationEntryPoint.commence(request, response, authenticationException);
- return;
- }
- }
-
- OAuth2Error error = ((OAuth2AuthenticationException) authenticationException).getError();
- ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
- if (OAuth2ErrorCodes.INVALID_CLIENT.equals(error.getErrorCode())) {
- httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
- }
- else {
- httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
- }
- // We don't want to reveal too much information to the caller so just return the
- // error code
- OAuth2Error errorResponse = new OAuth2Error(error.getErrorCode());
- this.errorHttpResponseConverter.write(errorResponse, null, httpResponse);
- }
-
private static void validateClientIdentifier(Authentication authentication) {
if (!(authentication instanceof OAuth2ClientAuthenticationToken)) {
return;
@@ -261,21 +223,4 @@ private static void validateClientIdentifier(Authentication authentication) {
}
}
- private static final class OAuth2ClientAuthenticationException extends OAuth2AuthenticationException {
-
- private final OAuth2ClientAuthenticationToken clientAuthentication;
-
- private OAuth2ClientAuthenticationException(OAuth2Error error, Throwable cause,
- OAuth2ClientAuthenticationToken clientAuthentication) {
- super(error, cause);
- Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
- this.clientAuthentication = clientAuthentication;
- }
-
- private OAuth2ClientAuthenticationToken getClientAuthentication() {
- return this.clientAuthentication;
- }
-
- }
-
}
diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2ClientAuthenticationFailureHandler.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2ClientAuthenticationFailureHandler.java
new file mode 100644
index 000000000..72e470a2d
--- /dev/null
+++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2ClientAuthenticationFailureHandler.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2020-2025 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.oauth2.server.authorization.web.authentication;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServletServerHttpResponse;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
+import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationException;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
+import org.springframework.util.Assert;
+
+/**
+ * An implementation of an {@link AuthenticationFailureHandler} used for handling a failed
+ * authentication attempt by an OAuth 2.0 Client and delegating to an
+ * {@link AuthenticationEntryPoint} based on the {@link ClientAuthenticationMethod} used
+ * by the client.
+ *
+ * @author Joe Grandja
+ * @since 1.5
+ * @see AuthenticationFailureHandler
+ * @see AuthenticationEntryPoint
+ * @see OAuth2ClientAuthenticationFilter
+ * @see OAuth2ClientAuthenticationException
+ */
+public final class OAuth2ClientAuthenticationFailureHandler implements AuthenticationFailureHandler {
+
+ private final Map authenticationEntryPoints;
+
+ private AuthenticationEntryPoint defaultAuthenticationEntryPoint = new DefaultAuthenticationEntryPoint();
+
+ public OAuth2ClientAuthenticationFailureHandler() {
+ this.authenticationEntryPoints = new HashMap<>();
+ BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
+ basicAuthenticationEntryPoint.setRealmName("default");
+ this.authenticationEntryPoints.put(ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
+ basicAuthenticationEntryPoint);
+ }
+
+ @Override
+ public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException authenticationException) throws IOException, ServletException {
+ SecurityContextHolder.clearContext();
+ AuthenticationEntryPoint authenticationEntryPoint = this.defaultAuthenticationEntryPoint;
+ if (authenticationException instanceof OAuth2ClientAuthenticationException clientAuthenticationException) {
+ OAuth2ClientAuthenticationToken clientAuthentication = clientAuthenticationException
+ .getClientAuthentication();
+ AuthenticationEntryPoint clientAuthenticationMethodEntryPoint = this.authenticationEntryPoints
+ .get(clientAuthentication.getClientAuthenticationMethod());
+ if (clientAuthenticationMethodEntryPoint != null) {
+ // Override the default
+ authenticationEntryPoint = clientAuthenticationMethodEntryPoint;
+ }
+ }
+ authenticationEntryPoint.commence(request, response, authenticationException);
+ }
+
+ /**
+ * Sets the {@link AuthenticationEntryPoint} used for the specified
+ * {@link ClientAuthenticationMethod}.
+ * @param authenticationEntryPoint the {@link AuthenticationEntryPoint}
+ * @param clientAuthenticationMethod the {@link ClientAuthenticationMethod}
+ */
+ public void setAuthenticationEntryPointFor(AuthenticationEntryPoint authenticationEntryPoint,
+ ClientAuthenticationMethod clientAuthenticationMethod) {
+ Assert.notNull(authenticationEntryPoint, "authenticationEntryPoint cannot be null");
+ Assert.notNull(clientAuthenticationMethod, "clientAuthenticationMethod cannot be null");
+ this.authenticationEntryPoints.put(clientAuthenticationMethod, authenticationEntryPoint);
+ }
+
+ /**
+ * Sets the default {@link AuthenticationEntryPoint} used when unable to determine the
+ * {@link ClientAuthenticationMethod} used by the client.
+ * @param defaultAuthenticationEntryPoint the default {@link AuthenticationEntryPoint}
+ */
+ public void setDefaultAuthenticationEntryPoint(AuthenticationEntryPoint defaultAuthenticationEntryPoint) {
+ Assert.notNull(defaultAuthenticationEntryPoint, "defaultAuthenticationEntryPoint cannot be null");
+ this.defaultAuthenticationEntryPoint = defaultAuthenticationEntryPoint;
+ }
+
+ private static final class DefaultAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+ private final HttpMessageConverter errorHttpResponseConverter = new OAuth2ErrorHttpMessageConverter();
+
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException exception) throws IOException {
+ OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
+ ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
+ if (OAuth2ErrorCodes.INVALID_CLIENT.equals(error.getErrorCode())) {
+ httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
+ }
+ else {
+ httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
+ }
+ // We don't want to reveal too much information to the caller
+ // so just return the error code
+ OAuth2Error errorResponse = new OAuth2Error(error.getErrorCode());
+ this.errorHttpResponseConverter.write(errorResponse, null, httpResponse);
+ }
+
+ }
+
+}
diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java
index f2ebe1151..269945fa0 100644
--- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java
+++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java
@@ -45,8 +45,10 @@
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
+import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2ClientAuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -142,7 +144,7 @@ public void doFilterWhenRequestDoesNotMatchThenNotProcessed() throws Exception {
}
@Test
- public void doFilterWhenRequestMatchesAndEmptyCredentialsThenNotProcessed() throws Exception {
+ public void doFilterWhenRequestMatchesAndEmptyCredentialsThenInvalidClientError() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("POST", this.filterProcessesUrl);
request.setServletPath(this.filterProcessesUrl);
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -150,8 +152,13 @@ public void doFilterWhenRequestMatchesAndEmptyCredentialsThenNotProcessed() thro
this.filter.doFilter(request, response, filterChain);
- verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
+ verifyNoInteractions(filterChain);
verifyNoInteractions(this.authenticationManager);
+
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
+ OAuth2Error error = readError(response);
+ assertThat(error.getErrorCode()).isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
}
@Test
@@ -237,6 +244,65 @@ public void doFilterWhenRequestMatchesAndBadCredentialsThenReturnChallenge() thr
assertThat(response.getHeader(HttpHeaders.WWW_AUTHENTICATE)).isEqualTo("Basic realm=\"default\"");
}
+ @Test
+ public void doFilterWhenRequestMatchesAndBadCredentialsAndCustomRealmConfiguredThenReturnChallenge()
+ throws Exception {
+ given(this.authenticationConverter.convert(any(HttpServletRequest.class)))
+ .willReturn(new OAuth2ClientAuthenticationToken("clientId", ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
+ "invalid-secret", null));
+ given(this.authenticationManager.authenticate(any(Authentication.class)))
+ .willThrow(new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT));
+
+ BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
+ basicAuthenticationEntryPoint.setRealmName("oauth2-client");
+ OAuth2ClientAuthenticationFailureHandler clientAuthenticationFailureHandler = new OAuth2ClientAuthenticationFailureHandler();
+ clientAuthenticationFailureHandler.setAuthenticationEntryPointFor(basicAuthenticationEntryPoint,
+ ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
+ this.filter.setAuthenticationFailureHandler(clientAuthenticationFailureHandler);
+
+ MockHttpServletRequest request = new MockHttpServletRequest("POST", this.filterProcessesUrl);
+ request.setServletPath(this.filterProcessesUrl);
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ FilterChain filterChain = mock(FilterChain.class);
+
+ this.filter.doFilter(request, response, filterChain);
+
+ verifyNoInteractions(filterChain);
+ verify(this.authenticationManager).authenticate(any());
+
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
+ assertThat(response.getHeader(HttpHeaders.WWW_AUTHENTICATE)).isEqualTo("Basic realm=\"oauth2-client\"");
+ }
+
+ @Test
+ public void doFilterWhenRequestMatchesAndNoCredentialsAndDefaultAuthenticationEntryPointOverriddenThenReturnChallenge()
+ throws Exception {
+ given(this.authenticationConverter.convert(any(HttpServletRequest.class))).willReturn(null);
+
+ BasicAuthenticationEntryPoint basicAuthenticationEntryPoint = new BasicAuthenticationEntryPoint();
+ basicAuthenticationEntryPoint.setRealmName("oauth2-client");
+ OAuth2ClientAuthenticationFailureHandler clientAuthenticationFailureHandler = new OAuth2ClientAuthenticationFailureHandler();
+ clientAuthenticationFailureHandler.setAuthenticationEntryPointFor(basicAuthenticationEntryPoint,
+ ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
+ clientAuthenticationFailureHandler.setDefaultAuthenticationEntryPoint(basicAuthenticationEntryPoint);
+ this.filter.setAuthenticationFailureHandler(clientAuthenticationFailureHandler);
+
+ MockHttpServletRequest request = new MockHttpServletRequest("POST", this.filterProcessesUrl);
+ request.setServletPath(this.filterProcessesUrl);
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ FilterChain filterChain = mock(FilterChain.class);
+
+ this.filter.doFilter(request, response, filterChain);
+
+ verifyNoInteractions(filterChain);
+ verifyNoInteractions(this.authenticationManager);
+
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
+ assertThat(response.getHeader(HttpHeaders.WWW_AUTHENTICATE)).isEqualTo("Basic realm=\"oauth2-client\"");
+ }
+
@Test
public void doFilterWhenRequestMatchesAndValidCredentialsThenProcessed() throws Exception {
final String remoteAddress = "remote-address";