oauth2Login WebFlux does not auto-redirect for XHR request
Fixes gh-8118
This commit is contained in:
parent
e00d3fcd62
commit
0230827335
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
|
@ -1180,24 +1180,56 @@ public class ServerHttpSecurity {
|
|||
authenticationFilter.setAuthenticationFailureHandler(getAuthenticationFailureHandler());
|
||||
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
|
||||
|
||||
MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(
|
||||
MediaType.TEXT_HTML);
|
||||
htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
Map<String, String> urlToText = http.oauth2Login.getLinks();
|
||||
String authenticationEntryPointRedirectPath;
|
||||
if (urlToText.size() == 1) {
|
||||
authenticationEntryPointRedirectPath = urlToText.keySet().iterator().next();
|
||||
} else {
|
||||
authenticationEntryPointRedirectPath = "/login";
|
||||
}
|
||||
RedirectServerAuthenticationEntryPoint entryPoint = new RedirectServerAuthenticationEntryPoint(authenticationEntryPointRedirectPath);
|
||||
entryPoint.setRequestCache(http.requestCache.requestCache);
|
||||
http.defaultEntryPoints.add(new DelegateEntry(htmlMatcher, entryPoint));
|
||||
setDefaultEntryPoints(http);
|
||||
|
||||
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
|
||||
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
|
||||
}
|
||||
|
||||
private void setDefaultEntryPoints(ServerHttpSecurity http) {
|
||||
String defaultLoginPage = "/login";
|
||||
Map<String, String> urlToText = http.oauth2Login.getLinks();
|
||||
String providerLoginPage = null;
|
||||
if (urlToText.size() == 1) {
|
||||
providerLoginPage = urlToText.keySet().iterator().next();
|
||||
}
|
||||
|
||||
MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(
|
||||
MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"),
|
||||
MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
|
||||
htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
|
||||
ServerWebExchangeMatcher xhrMatcher = exchange -> {
|
||||
if (exchange.getRequest().getHeaders().getOrEmpty("X-Requested-With").contains("XMLHttpRequest")) {
|
||||
return ServerWebExchangeMatcher.MatchResult.match();
|
||||
}
|
||||
return ServerWebExchangeMatcher.MatchResult.notMatch();
|
||||
};
|
||||
ServerWebExchangeMatcher notXhrMatcher = new NegatedServerWebExchangeMatcher(xhrMatcher);
|
||||
|
||||
ServerWebExchangeMatcher defaultEntryPointMatcher = new AndServerWebExchangeMatcher(
|
||||
notXhrMatcher, htmlMatcher);
|
||||
|
||||
if (providerLoginPage != null) {
|
||||
ServerWebExchangeMatcher loginPageMatcher = new PathPatternParserServerWebExchangeMatcher(defaultLoginPage);
|
||||
ServerWebExchangeMatcher faviconMatcher = new PathPatternParserServerWebExchangeMatcher("/favicon.ico");
|
||||
ServerWebExchangeMatcher defaultLoginPageMatcher = new AndServerWebExchangeMatcher(
|
||||
new OrServerWebExchangeMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher);
|
||||
|
||||
ServerWebExchangeMatcher matcher = new AndServerWebExchangeMatcher(
|
||||
notXhrMatcher, new NegatedServerWebExchangeMatcher(defaultLoginPageMatcher));
|
||||
RedirectServerAuthenticationEntryPoint entryPoint =
|
||||
new RedirectServerAuthenticationEntryPoint(providerLoginPage);
|
||||
entryPoint.setRequestCache(http.requestCache.requestCache);
|
||||
http.defaultEntryPoints.add(new DelegateEntry(matcher, entryPoint));
|
||||
}
|
||||
|
||||
RedirectServerAuthenticationEntryPoint defaultEntryPoint =
|
||||
new RedirectServerAuthenticationEntryPoint(defaultLoginPage);
|
||||
defaultEntryPoint.setRequestCache(http.requestCache.requestCache);
|
||||
http.defaultEntryPoints.add(new DelegateEntry(defaultEntryPointMatcher, defaultEntryPoint));
|
||||
}
|
||||
|
||||
private ServerAuthenticationSuccessHandler getAuthenticationSuccessHandler(ServerHttpSecurity http) {
|
||||
if (this.authenticationSuccessHandler == null) {
|
||||
RedirectServerAuthenticationSuccessHandler handler = new RedirectServerAuthenticationSuccessHandler();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
|
@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
|
@ -185,6 +186,22 @@ public class OAuth2LoginTests {
|
|||
assertThat(driver.getCurrentUrl()).startsWith("https://github.com/login/oauth/authorize");
|
||||
}
|
||||
|
||||
// gh-8118
|
||||
@Test
|
||||
public void defaultLoginPageWithSingleClientRegistrationAndXhrRequestThenDoesNotRedirectForAuthorization() {
|
||||
this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, WebFluxConfig.class).autowire();
|
||||
|
||||
this.client.get()
|
||||
.uri("/")
|
||||
.header("X-Requested-With", "XMLHttpRequest")
|
||||
.exchange()
|
||||
.expectStatus().is3xxRedirection()
|
||||
.expectHeader().valueEquals(HttpHeaders.LOCATION, "/login");
|
||||
}
|
||||
|
||||
@EnableWebFlux
|
||||
static class WebFluxConfig { }
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
static class OAuth2LoginWithSingleClientRegistrations {
|
||||
@Bean
|
||||
|
|
Loading…
Reference in New Issue