Fix CsrfConfigurer default AccessDeniedHandler consistency

Fix when AccessDeniedHandler is specified per RequestMatcher on
ExceptionHandlingConfigurer.

This introduces evolutions on :
- CsrfConfigurer#getDefaultAccessDeniedHandler,
to retrieve an AccessDeniedHandler similar to the one used by
ExceptionHandlingConfigurer.
- OAuth2ResourceServerConfigurer#accessDeniedHandler, to continue to
handle CsrfException with the default AccessDeniedHandler implementation

Fixes: gh-6511
This commit is contained in:
« Christophe 2021-08-03 11:20:03 +02:00 committed by Rob Winch
parent 0aa75e04b7
commit e85958f65c
3 changed files with 41 additions and 5 deletions

View File

@ -237,8 +237,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Gets the default {@link AccessDeniedHandler} from the
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
* {@link AccessDeniedHandlerImpl} if not available.
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler(HttpSecurityBuilder)} or
* create a {@link AccessDeniedHandlerImpl} if not available.
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
@ -247,7 +247,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
AccessDeniedHandler handler = null;
if (exceptionConfig != null) {
handler = exceptionConfig.getAccessDeniedHandler();
handler = exceptionConfig.getAccessDeniedHandler(http);
}
if (handler == null) {
handler = new AccessDeniedHandlerImpl();

View File

@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import jakarta.servlet.http.HttpServletRequest;
@ -51,6 +53,9 @@ import org.springframework.security.oauth2.server.resource.web.DefaultBearerToke
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfException;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
@ -153,7 +158,9 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
private OpaqueTokenConfigurer opaqueTokenConfigurer;
private AccessDeniedHandler accessDeniedHandler = new BearerTokenAccessDeniedHandler();
private AccessDeniedHandler accessDeniedHandler = new DelegatingAccessDeniedHandler(
new LinkedHashMap<>(Map.of(CsrfException.class, new AccessDeniedHandlerImpl())),
new BearerTokenAccessDeniedHandler());
private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -320,6 +320,17 @@ public class CsrfConfigurerTests {
any(HttpServletResponse.class), any());
}
@Test
public void getWhenCustomDefaultAccessDeniedHandlerForThenHandlerIsUsed() throws Exception {
DefaultAccessDeniedHandlerForConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);
DefaultAccessDeniedHandlerForConfig.MATCHER = mock(RequestMatcher.class);
given(DefaultAccessDeniedHandlerForConfig.MATCHER.matches(any())).willReturn(true);
this.spring.register(DefaultAccessDeniedHandlerForConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/")).andExpect(status().isOk());
verify(DefaultAccessDeniedHandlerForConfig.DENIED_HANDLER).handle(any(HttpServletRequest.class),
any(HttpServletResponse.class), any());
}
@Test
public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
@ -608,6 +619,24 @@ public class CsrfConfigurerTests {
}
@EnableWebSecurity
static class DefaultAccessDeniedHandlerForConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler DENIED_HANDLER;
static RequestMatcher MATCHER;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.exceptionHandling()
.defaultAccessDeniedHandlerFor(DENIED_HANDLER, MATCHER);
// @formatter:on
}
}
@EnableWebSecurity
static class FormLoginConfig extends WebSecurityConfigurerAdapter {