diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 15f0dd2996..9fac94fae1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -36,6 +36,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; @@ -85,9 +86,11 @@ import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtDecoderFactory; import org.springframework.security.oauth2.jwt.TestJwts; import org.springframework.security.web.FilterChainProxy; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.context.HttpRequestResponseHolder; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; +import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; @@ -401,6 +404,30 @@ public class OAuth2LoginConfigurerTests { assertThat(this.response.getRedirectedUrl()).doesNotMatch("http://localhost/oauth2/authorization/google"); } + @Test + public void oauth2LoginWithHttpBasicOneClientConfiguredAndRequestXHRNotAuthenticatedThenUnauthorized() + throws Exception { + loadConfig(OAuth2LoginWithHttpBasicConfig.class); + String requestUri = "/"; + this.request = new MockHttpServletRequest("GET", requestUri); + this.request.setServletPath(requestUri); + this.request.addHeader("X-Requested-With", "XMLHttpRequest"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + assertThat(this.response.getStatus()).isEqualTo(401); + } + + @Test + public void oauth2LoginWithXHREntryPointOneClientConfiguredAndRequestXHRNotAuthenticatedThenUnauthorized() + throws Exception { + loadConfig(OAuth2LoginWithXHREntryPointConfig.class); + String requestUri = "/"; + this.request = new MockHttpServletRequest("GET", requestUri); + this.request.setServletPath(requestUri); + this.request.addHeader("X-Requested-With", "XMLHttpRequest"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + assertThat(this.response.getStatus()).isEqualTo(401); + } + // gh-9457 @Test public void oauth2LoginWithOneAuthorizationCodeClientAndOtherClientsConfiguredThenRedirectForAuthorization() @@ -896,6 +923,45 @@ public class OAuth2LoginConfigurerTests { } + @EnableWebSecurity + static class OAuth2LoginWithHttpBasicConfig extends CommonWebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login() + .clientRegistrationRepository( + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) + .and() + .httpBasic(); + // @formatter:on + super.configure(http); + } + + } + + @EnableWebSecurity + static class OAuth2LoginWithXHREntryPointConfig extends CommonWebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login() + .clientRegistrationRepository( + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) + .and() + .exceptionHandling() + .defaultAuthenticationEntryPointFor( + new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), + new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest")); + // @formatter:on + super.configure(http); + } + + } + private abstract static class CommonWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { @Override diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java index 069271b878..dcf4761167 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java @@ -232,6 +232,19 @@ public class OAuth2LoginTests { // @formatter:on } + @Test + public void defaultLoginPageWithOAuth2LoginHttpBasicAndXhrRequestThenUnauthorized() { + this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, OAuth2LoginWithHttpBasic.class, + WebFluxConfig.class).autowire(); + // @formatter:off + this.client.get() + .uri("/") + .header("X-Requested-With", "XMLHttpRequest") + .exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + @Test public void oauth2AuthorizeWhenCustomObjectsThenUsed() { this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, OAuth2AuthorizeWithMockObjectsConfig.class, @@ -660,6 +673,30 @@ public class OAuth2LoginTests { } + @Configuration + static class OAuth2LoginWithHttpBasic { + + @Bean + SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { + ReactiveUserDetailsService reactiveUserDetailsService = ReactiveAuthenticationTestConfiguration + .userDetailsService(); + ReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager( + reactiveUserDetailsService); + http.authenticationManager(authenticationManager); + // @formatter:off + http + .authorizeExchange() + .anyExchange().authenticated() + .and() + .oauth2Login() + .and() + .httpBasic(); + // @formatter:on + return http.build(); + } + + } + @Configuration static class OAuth2LoginMockAuthenticationManagerConfig {