7 changed files with 175 additions and 64 deletions
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
/* |
||||
* Copyright 2020-2023 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 jakarta.servlet.ServletException; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
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.core.AuthenticationException; |
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException; |
||||
import org.springframework.security.oauth2.core.OAuth2Error; |
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter; |
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
||||
|
||||
/** |
||||
* A default implementation of an {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException} |
||||
* and returning the {@link OAuth2Error Error Response}. |
||||
* |
||||
* @author Dmitriy Dubson |
||||
* @see AuthenticationFailureHandler |
||||
* @since 1.2.0 |
||||
*/ |
||||
public final class OAuth2ErrorAuthenticationFailureHandler implements AuthenticationFailureHandler { |
||||
|
||||
private final Log logger = LogFactory.getLog(getClass()); |
||||
|
||||
private HttpMessageConverter<OAuth2Error> errorHttpResponseConverter = new OAuth2ErrorHttpMessageConverter(); |
||||
|
||||
@Override |
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException { |
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response); |
||||
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST); |
||||
|
||||
if (authenticationException instanceof OAuth2AuthenticationException) { |
||||
OAuth2Error error = ((OAuth2AuthenticationException) authenticationException).getError(); |
||||
this.errorHttpResponseConverter.write(error, null, httpResponse); |
||||
} else { |
||||
if (this.logger.isWarnEnabled()) { |
||||
this.logger.warn(LogMessage.format("Authentication exception must be of type 'org.springframework.security.oauth2.core.OAuth2AuthenticationException'. Provided exception was '%s'", authenticationException.getClass().getName())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets OAuth error HTTP message converter to write to upon authentication failure |
||||
* |
||||
* @param errorHttpResponseConverter the error HTTP message converter to set |
||||
*/ |
||||
public void setErrorHttpResponseConverter(HttpMessageConverter<OAuth2Error> errorHttpResponseConverter) { |
||||
this.errorHttpResponseConverter = errorHttpResponseConverter; |
||||
} |
||||
} |
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
/* |
||||
* Copyright 2020-2023 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 jakarta.servlet.ServletException; |
||||
import jakarta.servlet.http.HttpServletRequest; |
||||
import jakarta.servlet.http.HttpServletResponse; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.converter.HttpMessageConverter; |
||||
import org.springframework.http.server.ServletServerHttpResponse; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
import org.springframework.security.authentication.BadCredentialsException; |
||||
import org.springframework.security.core.AuthenticationException; |
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException; |
||||
import org.springframework.security.oauth2.core.OAuth2Error; |
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.ArgumentMatchers.isNull; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.verifyNoInteractions; |
||||
|
||||
/** |
||||
* Tests for {@link OAuth2ErrorAuthenticationFailureHandler} |
||||
* |
||||
* @author Dmitriy Dubson |
||||
*/ |
||||
public class OAuth2ErrorAuthenticationFailureHandlerTests { |
||||
|
||||
private HttpMessageConverter<OAuth2Error> errorHttpMessageConverter; |
||||
|
||||
private HttpServletRequest request; |
||||
|
||||
private HttpServletResponse response; |
||||
|
||||
@BeforeEach |
||||
@SuppressWarnings("unchecked") |
||||
public void setUp() { |
||||
errorHttpMessageConverter = (HttpMessageConverter<OAuth2Error>) mock(HttpMessageConverter.class); |
||||
request = new MockHttpServletRequest(); |
||||
response = new MockHttpServletResponse(); |
||||
} |
||||
|
||||
@Test |
||||
public void onAuthenticationFailure() throws IOException, ServletException { |
||||
OAuth2Error invalidRequestError = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST); |
||||
AuthenticationException authenticationException = new OAuth2AuthenticationException(invalidRequestError); |
||||
OAuth2ErrorAuthenticationFailureHandler handler = new OAuth2ErrorAuthenticationFailureHandler(); |
||||
handler.setErrorHttpResponseConverter(errorHttpMessageConverter); |
||||
|
||||
handler.onAuthenticationFailure(request, response, authenticationException); |
||||
|
||||
verify(errorHttpMessageConverter).write(eq(invalidRequestError), isNull(), any(ServletServerHttpResponse.class)); |
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); |
||||
} |
||||
|
||||
@Test |
||||
public void onAuthenticationFailure_ifExceptionProvidedIsNotOAuth2AuthenticationException() throws ServletException, IOException { |
||||
OAuth2ErrorAuthenticationFailureHandler handler = new OAuth2ErrorAuthenticationFailureHandler(); |
||||
handler.setErrorHttpResponseConverter(errorHttpMessageConverter); |
||||
|
||||
handler.onAuthenticationFailure(request, response, new BadCredentialsException("Not a valid exception.")); |
||||
|
||||
verifyNoInteractions(errorHttpMessageConverter); |
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue