parent
d2a37cb1d6
commit
519c15efb3
|
@ -38,6 +38,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
|
||||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||||
|
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||||
|
@ -78,6 +79,10 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||||
*/
|
*/
|
||||||
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||||
AbstractHttpConfigurer<HttpBasicConfigurer<B>, B> {
|
AbstractHttpConfigurer<HttpBasicConfigurer<B>, B> {
|
||||||
|
|
||||||
|
private static final RequestHeaderRequestMatcher X_REQUESTED_WITH = new RequestHeaderRequestMatcher("X-Requested-With",
|
||||||
|
"XMLHttpRequest");
|
||||||
|
|
||||||
private static final String DEFAULT_REALM = "Realm";
|
private static final String DEFAULT_REALM = "Realm";
|
||||||
|
|
||||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||||
|
@ -93,8 +98,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||||
realmName(DEFAULT_REALM);
|
realmName(DEFAULT_REALM);
|
||||||
|
|
||||||
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher, AuthenticationEntryPoint>();
|
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher, AuthenticationEntryPoint>();
|
||||||
entryPoints.put(new RequestHeaderRequestMatcher("X-Requested-With",
|
entryPoints.put(X_REQUESTED_WITH, new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
|
||||||
"XMLHttpRequest"), new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
|
|
||||||
|
|
||||||
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(
|
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(
|
||||||
entryPoints);
|
entryPoints);
|
||||||
|
@ -157,6 +161,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||||
if (contentNegotiationStrategy == null) {
|
if (contentNegotiationStrategy == null) {
|
||||||
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
|
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(
|
MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(
|
||||||
contentNegotiationStrategy, MediaType.APPLICATION_ATOM_XML,
|
contentNegotiationStrategy, MediaType.APPLICATION_ATOM_XML,
|
||||||
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
|
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
|
||||||
|
@ -167,9 +172,11 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||||
RequestMatcher notHtmlMatcher = new NegatedRequestMatcher(
|
RequestMatcher notHtmlMatcher = new NegatedRequestMatcher(
|
||||||
new MediaTypeRequestMatcher(contentNegotiationStrategy,
|
new MediaTypeRequestMatcher(contentNegotiationStrategy,
|
||||||
MediaType.TEXT_HTML));
|
MediaType.TEXT_HTML));
|
||||||
RequestMatcher preferredMatcher = new AndRequestMatcher(
|
RequestMatcher restNotHtmlMatcher = new AndRequestMatcher(
|
||||||
Arrays.<RequestMatcher>asList(notHtmlMatcher, restMatcher));
|
Arrays.<RequestMatcher>asList(notHtmlMatcher, restMatcher));
|
||||||
|
|
||||||
|
RequestMatcher preferredMatcher = new OrRequestMatcher(Arrays.asList(X_REQUESTED_WITH, restNotHtmlMatcher));
|
||||||
|
|
||||||
registerDefaultEntryPoint(http, preferredMatcher);
|
registerDefaultEntryPoint(http, preferredMatcher);
|
||||||
registerDefaultLogoutSuccessHandler(http, preferredMatcher);
|
registerDefaultLogoutSuccessHandler(http, preferredMatcher);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
|
||||||
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
|
||||||
then:
|
then:
|
||||||
def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
|
def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
|
||||||
entryPoints[0].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
|
entryPoints[0].requestMatchers[1].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
|
||||||
entryPoints[1].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
|
entryPoints[1].requestMatchers[1].contentNegotiationStrategy.class == HeaderContentNegotiationStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
|
||||||
then:
|
then:
|
||||||
def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
|
def entryPoints = delegateEntryPoint.entryPoints.keySet() as List
|
||||||
entryPoints[0].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
entryPoints[0].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||||
entryPoints[1].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
entryPoints[1].requestMatchers[1].requestMatchers[1].contentNegotiationStrategy == OverrideContentNegotiationStrategySharedObjectConfig.CNS
|
||||||
}
|
}
|
||||||
|
|
||||||
def "Override ContentNegotiationStrategy with @Bean"() {
|
def "Override ContentNegotiationStrategy with @Bean"() {
|
||||||
|
|
|
@ -232,4 +232,23 @@ class LogoutConfigurerTests extends BaseSpringSpec {
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class LogoutHandlerContentNegotiationForChrome extends WebSecurityConfigurerAdapter {
|
static class LogoutHandlerContentNegotiationForChrome extends WebSecurityConfigurerAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-3997
|
||||||
|
def "LogoutConfigurer for XMLHttpRequest is 204"() {
|
||||||
|
setup:
|
||||||
|
loadConfig(LogoutXMLHttpRequestConfig)
|
||||||
|
when:
|
||||||
|
login()
|
||||||
|
request.method = 'POST'
|
||||||
|
request.servletPath = '/logout'
|
||||||
|
request.addHeader('Accept', 'text/html,application/json')
|
||||||
|
request.addHeader('X-Requested-With', 'XMLHttpRequest')
|
||||||
|
springSecurityFilterChain.doFilter(request,response,chain)
|
||||||
|
then:
|
||||||
|
response.status == 204
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class LogoutXMLHttpRequestConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue