diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java index dd227be3c0..61f8388499 100644 --- a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java +++ b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java @@ -544,6 +544,14 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin assertThat(new Long(1L)).isEqualTo(result); } + protected Authentication getAuth() { + return this.auth; + } + + protected JdbcMutableAclService getJdbcMutableAclService() { + return this.jdbcMutableAclService; + } + /** * This class needed to show how to extend {@link JdbcMutableAclService} for * processing custom {@link Sid} implementations @@ -573,12 +581,4 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin } - protected Authentication getAuth() { - return this.auth; - } - - protected JdbcMutableAclService getJdbcMutableAclService() { - return this.jdbcMutableAclService; - } - } diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java index 0eefa06350..2e0ab5882d 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java @@ -53,6 +53,8 @@ import static org.springframework.security.test.web.servlet.response.SecurityMoc public class LdapAuthenticationProviderBuilderSecurityBuilderTests { + static Integer port; + @Rule public final SpringTestRule spring = new SpringTestRule(); @@ -76,6 +78,80 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("ROLE_"); } + @Test + public void groupRolesCustom() { + this.spring.register(GroupRolesConfig.class).autowire(); + LdapAuthenticationProvider provider = ldapProvider(); + + assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute")) + .isEqualTo("group"); + } + + @Test + public void groupSearchCustom() { + this.spring.register(GroupSearchConfig.class).autowire(); + LdapAuthenticationProvider provider = ldapProvider(); + + assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter")) + .isEqualTo("ou=groupName"); + } + + @Test + public void groupSubtreeSearchCustom() { + this.spring.register(GroupSubtreeSearchConfig.class).autowire(); + LdapAuthenticationProvider provider = ldapProvider(); + + assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "searchControls")) + .extracting("searchScope").isEqualTo(SearchControls.SUBTREE_SCOPE); + } + + @Test + public void rolePrefixCustom() { + this.spring.register(RolePrefixConfig.class).autowire(); + LdapAuthenticationProvider provider = ldapProvider(); + + assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("role_"); + } + + @Test + public void bindAuthentication() throws Exception { + this.spring.register(BindAuthenticationConfig.class).autowire(); + + this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated() + .withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")))); + } + + // SEC-2472 + @Test + public void canUseCryptoPasswordEncoder() throws Exception { + this.spring.register(PasswordEncoderConfig.class).autowire(); + + this.mockMvc.perform(formLogin().user("bcrypt").password("password")).andExpect(authenticated() + .withUsername("bcrypt").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")))); + } + + private LdapAuthenticationProvider ldapProvider() { + return ((List) ReflectionTestUtils.getField(this.authenticationManager, + "providers")).get(0); + } + + private LdapAuthoritiesPopulator getAuthoritiesPopulator(LdapAuthenticationProvider provider) { + return (LdapAuthoritiesPopulator) ReflectionTestUtils.getField(provider, "authoritiesPopulator"); + } + + private GrantedAuthoritiesMapper getAuthoritiesMapper(LdapAuthenticationProvider provider) { + return (GrantedAuthoritiesMapper) ReflectionTestUtils.getField(provider, "authoritiesMapper"); + } + + static int getPort() throws IOException { + if (port == null) { + ServerSocket socket = new ServerSocket(0); + port = socket.getLocalPort(); + socket.close(); + } + return port; + } + @EnableWebSecurity static class DefaultLdapConfig extends BaseLdapProviderConfig { @@ -91,15 +167,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - @Test - public void groupRolesCustom() { - this.spring.register(GroupRolesConfig.class).autowire(); - LdapAuthenticationProvider provider = ldapProvider(); - - assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute")) - .isEqualTo("group"); - } - @EnableWebSecurity static class GroupRolesConfig extends BaseLdapProviderConfig { @@ -116,15 +183,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - @Test - public void groupSearchCustom() { - this.spring.register(GroupSearchConfig.class).autowire(); - LdapAuthenticationProvider provider = ldapProvider(); - - assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter")) - .isEqualTo("ou=groupName"); - } - @EnableWebSecurity static class GroupSearchConfig extends BaseLdapProviderConfig { @@ -141,15 +199,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - @Test - public void groupSubtreeSearchCustom() { - this.spring.register(GroupSubtreeSearchConfig.class).autowire(); - LdapAuthenticationProvider provider = ldapProvider(); - - assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "searchControls")) - .extracting("searchScope").isEqualTo(SearchControls.SUBTREE_SCOPE); - } - @EnableWebSecurity static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig { @@ -167,14 +216,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - @Test - public void rolePrefixCustom() { - this.spring.register(RolePrefixConfig.class).autowire(); - LdapAuthenticationProvider provider = ldapProvider(); - - assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("role_"); - } - @EnableWebSecurity static class RolePrefixConfig extends BaseLdapProviderConfig { @@ -191,14 +232,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - @Test - public void bindAuthentication() throws Exception { - this.spring.register(BindAuthenticationConfig.class).autowire(); - - this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated() - .withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")))); - } - @EnableWebSecurity static class BindAuthenticationConfig extends BaseLdapServerConfig { @@ -216,15 +249,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - // SEC-2472 - @Test - public void canUseCryptoPasswordEncoder() throws Exception { - this.spring.register(PasswordEncoderConfig.class).autowire(); - - this.mockMvc.perform(formLogin().user("bcrypt").password("password")).andExpect(authenticated() - .withUsername("bcrypt").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")))); - } - @EnableWebSecurity static class PasswordEncoderConfig extends BaseLdapServerConfig { @@ -243,19 +267,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - private LdapAuthenticationProvider ldapProvider() { - return ((List) ReflectionTestUtils.getField(this.authenticationManager, - "providers")).get(0); - } - - private LdapAuthoritiesPopulator getAuthoritiesPopulator(LdapAuthenticationProvider provider) { - return (LdapAuthoritiesPopulator) ReflectionTestUtils.getField(provider, "authoritiesPopulator"); - } - - private GrantedAuthoritiesMapper getAuthoritiesMapper(LdapAuthenticationProvider provider) { - return (GrantedAuthoritiesMapper) ReflectionTestUtils.getField(provider, "authoritiesMapper"); - } - @EnableWebSecurity static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig { @@ -295,15 +306,4 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { } - static Integer port; - - static int getPort() throws IOException { - if (port == null) { - ServerSocket socket = new ServerSocket(0); - port = socket.getLocalPort(); - socket.close(); - } - return port; - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java index 60196d9fc7..0db78b0c52 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java @@ -379,6 +379,21 @@ public class LdapAuthenticationProviderConfigurer jwt) { if (this.jwtSpec == null) { this.jwtSpec = new JwtSpec(); @@ -244,45 +184,6 @@ public class RSocketSecurity { return this; } - public final class JwtSpec { - - private ReactiveAuthenticationManager authenticationManager; - - public JwtSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - return this; - } - - private ReactiveAuthenticationManager getAuthenticationManager() { - if (this.authenticationManager != null) { - return this.authenticationManager; - } - ReactiveJwtDecoder jwtDecoder = getBeanOrNull(ReactiveJwtDecoder.class); - if (jwtDecoder != null) { - this.authenticationManager = new JwtReactiveAuthenticationManager(jwtDecoder); - return this.authenticationManager; - } - return RSocketSecurity.this.authenticationManager; - } - - protected List build() { - ReactiveAuthenticationManager manager = getAuthenticationManager(); - AuthenticationPayloadInterceptor legacy = new AuthenticationPayloadInterceptor(manager); - legacy.setAuthenticationConverter(new BearerPayloadExchangeConverter()); - legacy.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder()); - - AuthenticationPayloadInterceptor standard = new AuthenticationPayloadInterceptor(manager); - standard.setAuthenticationConverter(new AuthenticationPayloadExchangeConverter()); - standard.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder()); - - return Arrays.asList(standard, legacy); - } - - private JwtSpec() { - } - - } - public RSocketSecurity authorizePayload(Customizer authorize) { if (this.authorizePayload == null) { this.authorizePayload = new AuthorizePayloadsSpec(); @@ -326,6 +227,131 @@ public class RSocketSecurity { return result; } + private T getBean(Class beanClass) { + if (this.context == null) { + return null; + } + return this.context.getBean(beanClass); + } + + private T getBeanOrNull(Class beanClass) { + return getBeanOrNull(ResolvableType.forClass(beanClass)); + } + + private T getBeanOrNull(ResolvableType type) { + if (this.context == null) { + return null; + } + String[] names = this.context.getBeanNamesForType(type); + if (names.length == 1) { + return (T) this.context.getBean(names[0]); + } + return null; + } + + protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.context = applicationContext; + } + + /** + * @since 5.3 + */ + public final class SimpleAuthenticationSpec { + + private ReactiveAuthenticationManager authenticationManager; + + public SimpleAuthenticationSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + return this; + } + + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager == null) { + return RSocketSecurity.this.authenticationManager; + } + return this.authenticationManager; + } + + protected AuthenticationPayloadInterceptor build() { + ReactiveAuthenticationManager manager = getAuthenticationManager(); + AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager); + result.setAuthenticationConverter(new AuthenticationPayloadExchangeConverter()); + result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder()); + return result; + } + + private SimpleAuthenticationSpec() { + } + + } + + public final class BasicAuthenticationSpec { + + private ReactiveAuthenticationManager authenticationManager; + + public BasicAuthenticationSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + return this; + } + + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager == null) { + return RSocketSecurity.this.authenticationManager; + } + return this.authenticationManager; + } + + protected AuthenticationPayloadInterceptor build() { + ReactiveAuthenticationManager manager = getAuthenticationManager(); + AuthenticationPayloadInterceptor result = new AuthenticationPayloadInterceptor(manager); + result.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder()); + return result; + } + + private BasicAuthenticationSpec() { + } + + } + + public final class JwtSpec { + + private ReactiveAuthenticationManager authenticationManager; + + public JwtSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + return this; + } + + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager != null) { + return this.authenticationManager; + } + ReactiveJwtDecoder jwtDecoder = getBeanOrNull(ReactiveJwtDecoder.class); + if (jwtDecoder != null) { + this.authenticationManager = new JwtReactiveAuthenticationManager(jwtDecoder); + return this.authenticationManager; + } + return RSocketSecurity.this.authenticationManager; + } + + protected List build() { + ReactiveAuthenticationManager manager = getAuthenticationManager(); + AuthenticationPayloadInterceptor legacy = new AuthenticationPayloadInterceptor(manager); + legacy.setAuthenticationConverter(new BearerPayloadExchangeConverter()); + legacy.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder()); + + AuthenticationPayloadInterceptor standard = new AuthenticationPayloadInterceptor(manager); + standard.setAuthenticationConverter(new AuthenticationPayloadExchangeConverter()); + standard.setOrder(PayloadInterceptorOrder.AUTHENTICATION.getOrder()); + + return Arrays.asList(standard, legacy); + } + + private JwtSpec() { + } + + } + public class AuthorizePayloadsSpec { private PayloadExchangeMatcherReactiveAuthorizationManager.Builder authzBuilder = PayloadExchangeMatcherReactiveAuthorizationManager @@ -417,30 +443,4 @@ public class RSocketSecurity { } - private T getBean(Class beanClass) { - if (this.context == null) { - return null; - } - return this.context.getBean(beanClass); - } - - private T getBeanOrNull(Class beanClass) { - return getBeanOrNull(ResolvableType.forClass(beanClass)); - } - - private T getBeanOrNull(ResolvableType type) { - if (this.context == null) { - return null; - } - String[] names = this.context.getBeanNamesForType(type); - if (names.length == 1) { - return (T) this.context.getBean(names[0]); - } - return null; - } - - protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.context = applicationContext; - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 2b5825bcb4..89a89f6d1c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -2912,6 +2912,24 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder> C getOrApply(C configurer) + throws Exception { + C existingConfig = (C) getConfigurer(configurer.getClass()); + if (existingConfig != null) { + return existingConfig; + } + return apply(configurer); + } + /** * An extension to {@link RequestMatcherConfigurer} that allows optionally configuring * the servlet path. @@ -2987,22 +3005,4 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder> C getOrApply(C configurer) - throws Exception { - C existingConfig = (C) getConfigurer(configurer.getClass()); - if (existingConfig != null) { - return existingConfig; - } - return apply(configurer); - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java index 9bb3e2183c..1a42d57849 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java @@ -304,6 +304,36 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder enableWebSecurityAttrMap = importMetadata + .getAnnotationAttributes(EnableWebSecurity.class.getName()); + AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap); + this.debugEnabled = enableWebSecurityAttrs.getBoolean("debug"); + if (this.webSecurity != null) { + this.webSecurity.debug(this.debugEnabled); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java. + * lang.ClassLoader) + */ + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + /** * A custom verision of the Spring provided AnnotationAwareOrderComparator that uses * {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class @@ -221,33 +250,4 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa } - /* - * (non-Javadoc) - * - * @see org.springframework.context.annotation.ImportAware#setImportMetadata(org. - * springframework.core.type.AnnotationMetadata) - */ - @Override - public void setImportMetadata(AnnotationMetadata importMetadata) { - Map enableWebSecurityAttrMap = importMetadata - .getAnnotationAttributes(EnableWebSecurity.class.getName()); - AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap); - this.debugEnabled = enableWebSecurityAttrs.getBoolean("debug"); - if (this.webSecurity != null) { - this.webSecurity.debug(this.debugEnabled); - } - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java. - * lang.ClassLoader) - */ - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java index dd1d6bc749..5927eb8be6 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java @@ -102,44 +102,6 @@ abstract class AbstractInterceptUrlConfigurer> getDecisionVoters(H http); - abstract class AbstractInterceptUrlRegistry, T> - extends AbstractConfigAttributeRequestMatcherRegistry { - - /** - * Allows setting the {@link AccessDecisionManager}. If none is provided, a - * default {@link AccessDecisionManager} is created. - * @param accessDecisionManager the {@link AccessDecisionManager} to use - * @return the {@link AbstractInterceptUrlConfigurer} for further customization - */ - public R accessDecisionManager(AccessDecisionManager accessDecisionManager) { - AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager; - return getSelf(); - } - - /** - * Allows setting if the {@link FilterSecurityInterceptor} should be only applied - * once per request (i.e. if the filter intercepts on a forward, should it be - * applied again). - * @param filterSecurityInterceptorOncePerRequest if the - * {@link FilterSecurityInterceptor} should be only applied once per request - * @return the {@link AbstractInterceptUrlConfigurer} for further customization - */ - public R filterSecurityInterceptorOncePerRequest(boolean filterSecurityInterceptorOncePerRequest) { - AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest; - return getSelf(); - } - - /** - * Returns a reference to the current object with a single suppression of the type - * @return a reference to the current object - */ - @SuppressWarnings("unchecked") - private R getSelf() { - return (R) this; - } - - } - /** * Creates the default {@code AccessDecisionManager} * @return the default {@code AccessDecisionManager} @@ -182,4 +144,42 @@ abstract class AbstractInterceptUrlConfigurer, T> + extends AbstractConfigAttributeRequestMatcherRegistry { + + /** + * Allows setting the {@link AccessDecisionManager}. If none is provided, a + * default {@link AccessDecisionManager} is created. + * @param accessDecisionManager the {@link AccessDecisionManager} to use + * @return the {@link AbstractInterceptUrlConfigurer} for further customization + */ + public R accessDecisionManager(AccessDecisionManager accessDecisionManager) { + AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager; + return getSelf(); + } + + /** + * Allows setting if the {@link FilterSecurityInterceptor} should be only applied + * once per request (i.e. if the filter intercepts on a forward, should it be + * applied again). + * @param filterSecurityInterceptorOncePerRequest if the + * {@link FilterSecurityInterceptor} should be only applied once per request + * @return the {@link AbstractInterceptUrlConfigurer} for further customization + */ + public R filterSecurityInterceptorOncePerRequest(boolean filterSecurityInterceptorOncePerRequest) { + AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest; + return getSelf(); + } + + /** + * Returns a reference to the current object with a single suppression of the type + * @return a reference to the current object + */ + @SuppressWarnings("unchecked") + private R getSelf() { + return (R) this; + } + + } + } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java index d75c6d44b4..34844a74b2 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java @@ -109,61 +109,6 @@ public final class ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { - - /** - * @param context - */ - private ExpressionInterceptUrlRegistry(ApplicationContext context) { - setApplicationContext(context); - } - - @Override - public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) { - return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns)); - } - - @Override - public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) { - return mvcMatchers(null, patterns); - } - - @Override - protected AuthorizedUrl chainRequestMatchersInternal(List requestMatchers) { - return new AuthorizedUrl(requestMatchers); - } - - /** - * Allows customization of the {@link SecurityExpressionHandler} to be used. The - * default is {@link DefaultWebSecurityExpressionHandler} - * @param expressionHandler the {@link SecurityExpressionHandler} to be used - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization. - */ - public ExpressionInterceptUrlRegistry expressionHandler( - SecurityExpressionHandler expressionHandler) { - ExpressionUrlAuthorizationConfigurer.this.expressionHandler = expressionHandler; - return this; - } - - /** - * Adds an {@link ObjectPostProcessor} for this class. - * @param objectPostProcessor - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customizations - */ - public ExpressionInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - addObjectPostProcessor(objectPostProcessor); - return this; - } - - public H and() { - return ExpressionUrlAuthorizationConfigurer.this.and(); - } - - } - /** * Allows registering multiple {@link RequestMatcher} instances to a collection of * {@link ConfigAttribute} instances @@ -261,6 +206,61 @@ public final class ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { + + /** + * @param context + */ + private ExpressionInterceptUrlRegistry(ApplicationContext context) { + setApplicationContext(context); + } + + @Override + public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) { + return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns)); + } + + @Override + public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) { + return mvcMatchers(null, patterns); + } + + @Override + protected AuthorizedUrl chainRequestMatchersInternal(List requestMatchers) { + return new AuthorizedUrl(requestMatchers); + } + + /** + * Allows customization of the {@link SecurityExpressionHandler} to be used. The + * default is {@link DefaultWebSecurityExpressionHandler} + * @param expressionHandler the {@link SecurityExpressionHandler} to be used + * @return the {@link ExpressionUrlAuthorizationConfigurer} for further + * customization. + */ + public ExpressionInterceptUrlRegistry expressionHandler( + SecurityExpressionHandler expressionHandler) { + ExpressionUrlAuthorizationConfigurer.this.expressionHandler = expressionHandler; + return this; + } + + /** + * Adds an {@link ObjectPostProcessor} for this class. + * @param objectPostProcessor + * @return the {@link ExpressionUrlAuthorizationConfigurer} for further + * customizations + */ + public ExpressionInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { + addObjectPostProcessor(objectPostProcessor); + return this; + } + + public H and() { + return ExpressionUrlAuthorizationConfigurer.this.and(); + } + + } + /** * An {@link AuthorizedUrl} that allows optionally configuring the * {@link MvcRequestMatcher#setMethod(HttpMethod)} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java index 5c9e997931..3a88e03e8f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java @@ -145,6 +145,357 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } + /** + * Note this is not comprehensive XSS protection! + * + *

+ * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the X-XSS-Protection header + *

+ * @return the {@link XXssConfig} for additional customizations + */ + public XXssConfig xssProtection() { + return this.xssProtection.enable(); + } + + /** + * Note this is not comprehensive XSS protection! + * + *

+ * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the X-XSS-Protection header + *

+ * @param xssCustomizer the {@link Customizer} to provide more options for the + * {@link XXssConfig} + * @return the {@link HeadersConfigurer} for additional customizations + */ + public HeadersConfigurer xssProtection(Customizer xssCustomizer) { + xssCustomizer.customize(this.xssProtection.enable()); + return HeadersConfigurer.this; + } + + /** + * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the + * following headers: + *
    + *
  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  • + *
  • Pragma: no-cache
  • + *
  • Expires: 0
  • + *
+ * @return the {@link CacheControlConfig} for additional customizations + */ + public CacheControlConfig cacheControl() { + return this.cacheControl.enable(); + } + + /** + * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the + * following headers: + *
    + *
  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  • + *
  • Pragma: no-cache
  • + *
  • Expires: 0
  • + *
+ * @param cacheControlCustomizer the {@link Customizer} to provide more options for + * the {@link CacheControlConfig} + * @return the {@link HeadersConfigurer} for additional customizations + */ + public HeadersConfigurer cacheControl(Customizer cacheControlCustomizer) { + cacheControlCustomizer.customize(this.cacheControl.enable()); + return HeadersConfigurer.this; + } + + /** + * Allows customizing the {@link HstsHeaderWriter} which provides support for + * HTTP Strict Transport Security + * (HSTS). + * @return the {@link HstsConfig} for additional customizations + */ + public HstsConfig httpStrictTransportSecurity() { + return this.hsts.enable(); + } + + /** + * Allows customizing the {@link HstsHeaderWriter} which provides support for + * HTTP Strict Transport Security + * (HSTS). + * @param hstsCustomizer the {@link Customizer} to provide more options for the + * {@link HstsConfig} + * @return the {@link HeadersConfigurer} for additional customizations + */ + public HeadersConfigurer httpStrictTransportSecurity(Customizer hstsCustomizer) { + hstsCustomizer.customize(this.hsts.enable()); + return HeadersConfigurer.this; + } + + /** + * Allows customizing the {@link XFrameOptionsHeaderWriter}. + * @return the {@link FrameOptionsConfig} for additional customizations + */ + public FrameOptionsConfig frameOptions() { + return this.frameOptions.enable(); + } + + /** + * Allows customizing the {@link XFrameOptionsHeaderWriter}. + * @param frameOptionsCustomizer the {@link Customizer} to provide more options for + * the {@link FrameOptionsConfig} + * @return the {@link HeadersConfigurer} for additional customizations + */ + public HeadersConfigurer frameOptions(Customizer frameOptionsCustomizer) { + frameOptionsCustomizer.customize(this.frameOptions.enable()); + return HeadersConfigurer.this; + } + + /** + * Allows customizing the {@link HpkpHeaderWriter} which provides support for + * HTTP Public Key Pinning (HPKP). + * @return the {@link HpkpConfig} for additional customizations + * + * @since 4.1 + */ + public HpkpConfig httpPublicKeyPinning() { + return this.hpkp.enable(); + } + + /** + * Allows customizing the {@link HpkpHeaderWriter} which provides support for + * HTTP Public Key Pinning (HPKP). + * @param hpkpCustomizer the {@link Customizer} to provide more options for the + * {@link HpkpConfig} + * @return the {@link HeadersConfigurer} for additional customizations + */ + public HeadersConfigurer httpPublicKeyPinning(Customizer hpkpCustomizer) { + hpkpCustomizer.customize(this.hpkp.enable()); + return HeadersConfigurer.this; + } + + /** + *

+ * Allows configuration for Content Security + * Policy (CSP) Level 2. + *

+ * + *

+ * Calling this method automatically enables (includes) the Content-Security-Policy + * header in the response using the supplied security policy directive(s). + *

+ * + *

+ * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which + * supports the writing of the two headers as detailed in the W3C Candidate + * Recommendation: + *

+ *
    + *
  • Content-Security-Policy
  • + *
  • Content-Security-Policy-Report-Only
  • + *
+ * @return the {@link ContentSecurityPolicyConfig} for additional configuration + * @throws IllegalArgumentException if policyDirectives is null or empty + * @since 4.1 + * @see ContentSecurityPolicyHeaderWriter + */ + public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) { + this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives); + return this.contentSecurityPolicy; + } + + /** + *

+ * Allows configuration for Content Security + * Policy (CSP) Level 2. + *

+ * + *

+ * Calling this method automatically enables (includes) the Content-Security-Policy + * header in the response using the supplied security policy directive(s). + *

+ * + *

+ * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which + * supports the writing of the two headers as detailed in the W3C Candidate + * Recommendation: + *

+ *
    + *
  • Content-Security-Policy
  • + *
  • Content-Security-Policy-Report-Only
  • + *
+ * @param contentSecurityCustomizer the {@link Customizer} to provide more options for + * the {@link ContentSecurityPolicyConfig} + * @return the {@link HeadersConfigurer} for additional customizations + * @see ContentSecurityPolicyHeaderWriter + */ + public HeadersConfigurer contentSecurityPolicy( + Customizer contentSecurityCustomizer) { + this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(); + contentSecurityCustomizer.customize(this.contentSecurityPolicy); + + return HeadersConfigurer.this; + } + + /** + * Clears all of the default headers from the response. After doing so, one can add + * headers back. For example, if you only want to use Spring Security's cache control + * you can use the following: + * + *
+	 * http.headers().defaultsDisabled().cacheControl();
+	 * 
+ * @return the {@link HeadersConfigurer} for additional customization + */ + public HeadersConfigurer defaultsDisabled() { + this.contentTypeOptions.disable(); + this.xssProtection.disable(); + this.cacheControl.disable(); + this.hsts.disable(); + this.frameOptions.disable(); + return this; + } + + @Override + public void configure(H http) { + HeaderWriterFilter headersFilter = createHeaderWriterFilter(); + http.addFilter(headersFilter); + } + + /** + * Creates the {@link HeaderWriter} + * @return the {@link HeaderWriter} + */ + private HeaderWriterFilter createHeaderWriterFilter() { + List writers = getHeaderWriters(); + if (writers.isEmpty()) { + throw new IllegalStateException( + "Headers security is enabled, but no headers will be added. Either add headers or disable headers security"); + } + HeaderWriterFilter headersFilter = new HeaderWriterFilter(writers); + headersFilter = postProcess(headersFilter); + return headersFilter; + } + + /** + * Gets the {@link HeaderWriter} instances and possibly initializes with the defaults. + * @return + */ + private List getHeaderWriters() { + List writers = new ArrayList<>(); + addIfNotNull(writers, this.contentTypeOptions.writer); + addIfNotNull(writers, this.xssProtection.writer); + addIfNotNull(writers, this.cacheControl.writer); + addIfNotNull(writers, this.hsts.writer); + addIfNotNull(writers, this.frameOptions.writer); + addIfNotNull(writers, this.hpkp.writer); + addIfNotNull(writers, this.contentSecurityPolicy.writer); + addIfNotNull(writers, this.referrerPolicy.writer); + addIfNotNull(writers, this.featurePolicy.writer); + writers.addAll(this.headerWriters); + return writers; + } + + private void addIfNotNull(List values, T value) { + if (value != null) { + values.add(value); + } + } + + /** + *

+ * Allows configuration for Referrer + * Policy. + *

+ * + *

+ * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support + * the writing of the header as detailed in the W3C Technical Report: + *

+ *
    + *
  • Referrer-Policy
  • + *
+ * + *

+ * Default value is: + *

+ * + *
+	 * Referrer-Policy: no-referrer
+	 * 
+ * @return the {@link ReferrerPolicyConfig} for additional configuration + * @since 4.2 + * @see ReferrerPolicyHeaderWriter + */ + public ReferrerPolicyConfig referrerPolicy() { + this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(); + return this.referrerPolicy; + } + + /** + *

+ * Allows configuration for Referrer + * Policy. + *

+ * + *

+ * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support + * the writing of the header as detailed in the W3C Technical Report: + *

+ *
    + *
  • Referrer-Policy
  • + *
+ * @return the {@link ReferrerPolicyConfig} for additional configuration + * @throws IllegalArgumentException if policy is null or empty + * @since 4.2 + * @see ReferrerPolicyHeaderWriter + */ + public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) { + this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy); + return this.referrerPolicy; + } + + /** + *

+ * Allows configuration for Referrer + * Policy. + *

+ * + *

+ * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support + * the writing of the header as detailed in the W3C Technical Report: + *

+ *
    + *
  • Referrer-Policy
  • + *
+ * @param referrerPolicyCustomizer the {@link Customizer} to provide more options for + * the {@link ReferrerPolicyConfig} + * @return the {@link HeadersConfigurer} for additional customizations + * @see ReferrerPolicyHeaderWriter + */ + public HeadersConfigurer referrerPolicy(Customizer referrerPolicyCustomizer) { + this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(); + referrerPolicyCustomizer.customize(this.referrerPolicy); + return HeadersConfigurer.this; + } + + /** + * Allows configuration for Feature + * Policy. + *

+ * Calling this method automatically enables (includes) the {@code Feature-Policy} + * header in the response using the supplied policy directive(s). + *

+ * Configuration is provided to the {@link FeaturePolicyHeaderWriter} which is + * responsible for writing the header. + * @return the {@link FeaturePolicyConfig} for additional configuration + * @throws IllegalArgumentException if policyDirectives is {@code null} or empty + * @since 5.1 + * @see FeaturePolicyHeaderWriter + */ + public FeaturePolicyConfig featurePolicy(String policyDirectives) { + this.featurePolicy.writer = new FeaturePolicyHeaderWriter(policyDirectives); + return this.featurePolicy; + } + public final class ContentTypeOptionsConfig { private XContentTypeOptionsHeaderWriter writer; @@ -183,37 +534,6 @@ public class HeadersConfigurer> } - /** - * Note this is not comprehensive XSS protection! - * - *

- * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the X-XSS-Protection header - *

- * @return the {@link XXssConfig} for additional customizations - */ - public XXssConfig xssProtection() { - return this.xssProtection.enable(); - } - - /** - * Note this is not comprehensive XSS protection! - * - *

- * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the X-XSS-Protection header - *

- * @param xssCustomizer the {@link Customizer} to provide more options for the - * {@link XXssConfig} - * @return the {@link HeadersConfigurer} for additional customizations - */ - public HeadersConfigurer xssProtection(Customizer xssCustomizer) { - xssCustomizer.customize(this.xssProtection.enable()); - return HeadersConfigurer.this; - } - public final class XXssConfig { private XXssProtectionHeaderWriter writer; @@ -291,37 +611,6 @@ public class HeadersConfigurer> } - /** - * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the - * following headers: - *
    - *
  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  • - *
  • Pragma: no-cache
  • - *
  • Expires: 0
  • - *
- * @return the {@link CacheControlConfig} for additional customizations - */ - public CacheControlConfig cacheControl() { - return this.cacheControl.enable(); - } - - /** - * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the - * following headers: - *
    - *
  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  • - *
  • Pragma: no-cache
  • - *
  • Expires: 0
  • - *
- * @param cacheControlCustomizer the {@link Customizer} to provide more options for - * the {@link CacheControlConfig} - * @return the {@link HeadersConfigurer} for additional customizations - */ - public HeadersConfigurer cacheControl(Customizer cacheControlCustomizer) { - cacheControlCustomizer.customize(this.cacheControl.enable()); - return HeadersConfigurer.this; - } - public final class CacheControlConfig { private CacheControlHeadersWriter writer; @@ -361,29 +650,6 @@ public class HeadersConfigurer> } - /** - * Allows customizing the {@link HstsHeaderWriter} which provides support for - * HTTP Strict Transport Security - * (HSTS). - * @return the {@link HstsConfig} for additional customizations - */ - public HstsConfig httpStrictTransportSecurity() { - return this.hsts.enable(); - } - - /** - * Allows customizing the {@link HstsHeaderWriter} which provides support for - * HTTP Strict Transport Security - * (HSTS). - * @param hstsCustomizer the {@link Customizer} to provide more options for the - * {@link HstsConfig} - * @return the {@link HeadersConfigurer} for additional customizations - */ - public HeadersConfigurer httpStrictTransportSecurity(Customizer hstsCustomizer) { - hstsCustomizer.customize(this.hsts.enable()); - return HeadersConfigurer.this; - } - public final class HstsConfig { private HstsHeaderWriter writer; @@ -491,25 +757,6 @@ public class HeadersConfigurer> } - /** - * Allows customizing the {@link XFrameOptionsHeaderWriter}. - * @return the {@link FrameOptionsConfig} for additional customizations - */ - public FrameOptionsConfig frameOptions() { - return this.frameOptions.enable(); - } - - /** - * Allows customizing the {@link XFrameOptionsHeaderWriter}. - * @param frameOptionsCustomizer the {@link Customizer} to provide more options for - * the {@link FrameOptionsConfig} - * @return the {@link HeadersConfigurer} for additional customizations - */ - public HeadersConfigurer frameOptions(Customizer frameOptionsCustomizer) { - frameOptionsCustomizer.customize(this.frameOptions.enable()); - return HeadersConfigurer.this; - } - public final class FrameOptionsConfig { private XFrameOptionsHeaderWriter writer; @@ -571,29 +818,6 @@ public class HeadersConfigurer> } - /** - * Allows customizing the {@link HpkpHeaderWriter} which provides support for - * HTTP Public Key Pinning (HPKP). - * @return the {@link HpkpConfig} for additional customizations - * - * @since 4.1 - */ - public HpkpConfig httpPublicKeyPinning() { - return this.hpkp.enable(); - } - - /** - * Allows customizing the {@link HpkpHeaderWriter} which provides support for - * HTTP Public Key Pinning (HPKP). - * @param hpkpCustomizer the {@link Customizer} to provide more options for the - * {@link HpkpConfig} - * @return the {@link HeadersConfigurer} for additional customizations - */ - public HeadersConfigurer httpPublicKeyPinning(Customizer hpkpCustomizer) { - hpkpCustomizer.customize(this.hpkp.enable()); - return HeadersConfigurer.this; - } - public final class HpkpConfig { private HpkpHeaderWriter writer; @@ -761,69 +985,6 @@ public class HeadersConfigurer> } - /** - *

- * Allows configuration for Content Security - * Policy (CSP) Level 2. - *

- * - *

- * Calling this method automatically enables (includes) the Content-Security-Policy - * header in the response using the supplied security policy directive(s). - *

- * - *

- * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which - * supports the writing of the two headers as detailed in the W3C Candidate - * Recommendation: - *

- *
    - *
  • Content-Security-Policy
  • - *
  • Content-Security-Policy-Report-Only
  • - *
- * @return the {@link ContentSecurityPolicyConfig} for additional configuration - * @throws IllegalArgumentException if policyDirectives is null or empty - * @since 4.1 - * @see ContentSecurityPolicyHeaderWriter - */ - public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) { - this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives); - return this.contentSecurityPolicy; - } - - /** - *

- * Allows configuration for Content Security - * Policy (CSP) Level 2. - *

- * - *

- * Calling this method automatically enables (includes) the Content-Security-Policy - * header in the response using the supplied security policy directive(s). - *

- * - *

- * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which - * supports the writing of the two headers as detailed in the W3C Candidate - * Recommendation: - *

- *
    - *
  • Content-Security-Policy
  • - *
  • Content-Security-Policy-Report-Only
  • - *
- * @param contentSecurityCustomizer the {@link Customizer} to provide more options for - * the {@link ContentSecurityPolicyConfig} - * @return the {@link HeadersConfigurer} for additional customizations - * @see ContentSecurityPolicyHeaderWriter - */ - public HeadersConfigurer contentSecurityPolicy( - Customizer contentSecurityCustomizer) { - this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(); - contentSecurityCustomizer.customize(this.contentSecurityPolicy); - - return HeadersConfigurer.this; - } - public final class ContentSecurityPolicyConfig { private ContentSecurityPolicyHeaderWriter writer; @@ -863,148 +1024,6 @@ public class HeadersConfigurer> } - /** - * Clears all of the default headers from the response. After doing so, one can add - * headers back. For example, if you only want to use Spring Security's cache control - * you can use the following: - * - *
-	 * http.headers().defaultsDisabled().cacheControl();
-	 * 
- * @return the {@link HeadersConfigurer} for additional customization - */ - public HeadersConfigurer defaultsDisabled() { - this.contentTypeOptions.disable(); - this.xssProtection.disable(); - this.cacheControl.disable(); - this.hsts.disable(); - this.frameOptions.disable(); - return this; - } - - @Override - public void configure(H http) { - HeaderWriterFilter headersFilter = createHeaderWriterFilter(); - http.addFilter(headersFilter); - } - - /** - * Creates the {@link HeaderWriter} - * @return the {@link HeaderWriter} - */ - private HeaderWriterFilter createHeaderWriterFilter() { - List writers = getHeaderWriters(); - if (writers.isEmpty()) { - throw new IllegalStateException( - "Headers security is enabled, but no headers will be added. Either add headers or disable headers security"); - } - HeaderWriterFilter headersFilter = new HeaderWriterFilter(writers); - headersFilter = postProcess(headersFilter); - return headersFilter; - } - - /** - * Gets the {@link HeaderWriter} instances and possibly initializes with the defaults. - * @return - */ - private List getHeaderWriters() { - List writers = new ArrayList<>(); - addIfNotNull(writers, this.contentTypeOptions.writer); - addIfNotNull(writers, this.xssProtection.writer); - addIfNotNull(writers, this.cacheControl.writer); - addIfNotNull(writers, this.hsts.writer); - addIfNotNull(writers, this.frameOptions.writer); - addIfNotNull(writers, this.hpkp.writer); - addIfNotNull(writers, this.contentSecurityPolicy.writer); - addIfNotNull(writers, this.referrerPolicy.writer); - addIfNotNull(writers, this.featurePolicy.writer); - writers.addAll(this.headerWriters); - return writers; - } - - private void addIfNotNull(List values, T value) { - if (value != null) { - values.add(value); - } - } - - /** - *

- * Allows configuration for Referrer - * Policy. - *

- * - *

- * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support - * the writing of the header as detailed in the W3C Technical Report: - *

- *
    - *
  • Referrer-Policy
  • - *
- * - *

- * Default value is: - *

- * - *
-	 * Referrer-Policy: no-referrer
-	 * 
- * @return the {@link ReferrerPolicyConfig} for additional configuration - * @since 4.2 - * @see ReferrerPolicyHeaderWriter - */ - public ReferrerPolicyConfig referrerPolicy() { - this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(); - return this.referrerPolicy; - } - - /** - *

- * Allows configuration for Referrer - * Policy. - *

- * - *

- * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support - * the writing of the header as detailed in the W3C Technical Report: - *

- *
    - *
  • Referrer-Policy
  • - *
- * @return the {@link ReferrerPolicyConfig} for additional configuration - * @throws IllegalArgumentException if policy is null or empty - * @since 4.2 - * @see ReferrerPolicyHeaderWriter - */ - public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) { - this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy); - return this.referrerPolicy; - } - - /** - *

- * Allows configuration for Referrer - * Policy. - *

- * - *

- * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support - * the writing of the header as detailed in the W3C Technical Report: - *

- *
    - *
  • Referrer-Policy
  • - *
- * @param referrerPolicyCustomizer the {@link Customizer} to provide more options for - * the {@link ReferrerPolicyConfig} - * @return the {@link HeadersConfigurer} for additional customizations - * @see ReferrerPolicyHeaderWriter - */ - public HeadersConfigurer referrerPolicy(Customizer referrerPolicyCustomizer) { - this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(); - referrerPolicyCustomizer.customize(this.referrerPolicy); - return HeadersConfigurer.this; - } - public final class ReferrerPolicyConfig { private ReferrerPolicyHeaderWriter writer; @@ -1029,25 +1048,6 @@ public class HeadersConfigurer> } - /** - * Allows configuration for Feature - * Policy. - *

- * Calling this method automatically enables (includes) the {@code Feature-Policy} - * header in the response using the supplied policy directive(s). - *

- * Configuration is provided to the {@link FeaturePolicyHeaderWriter} which is - * responsible for writing the header. - * @return the {@link FeaturePolicyConfig} for additional configuration - * @throws IllegalArgumentException if policyDirectives is {@code null} or empty - * @since 5.1 - * @see FeaturePolicyHeaderWriter - */ - public FeaturePolicyConfig featurePolicy(String policyDirectives) { - this.featurePolicy.writer = new FeaturePolicyHeaderWriter(policyDirectives); - return this.featurePolicy; - } - public final class FeaturePolicyConfig { private FeaturePolicyHeaderWriter writer; diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java index 4cd029d56a..c38d6fbc96 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java @@ -311,144 +311,6 @@ public final class SessionManagementConfigurer> this.sessionFixationAuthenticationStrategy = postProcess(sessionFixationAuthenticationStrategy); } - /** - * Allows configuring SessionFixation protection - * - * @author Rob Winch - */ - public final class SessionFixationConfigurer { - - /** - * Specifies that a new session should be created, but the session attributes from - * the original {@link HttpSession} should not be retained. - * @return the {@link SessionManagementConfigurer} for further customizations - */ - public SessionManagementConfigurer newSession() { - SessionFixationProtectionStrategy sessionFixationProtectionStrategy = new SessionFixationProtectionStrategy(); - sessionFixationProtectionStrategy.setMigrateSessionAttributes(false); - setSessionFixationAuthenticationStrategy(sessionFixationProtectionStrategy); - return SessionManagementConfigurer.this; - } - - /** - * Specifies that a new session should be created and the session attributes from - * the original {@link HttpSession} should be retained. - * @return the {@link SessionManagementConfigurer} for further customizations - */ - public SessionManagementConfigurer migrateSession() { - setSessionFixationAuthenticationStrategy(new SessionFixationProtectionStrategy()); - return SessionManagementConfigurer.this; - } - - /** - * Specifies that the Servlet container-provided session fixation protection - * should be used. When a session authenticates, the Servlet method - * {@code HttpServletRequest#changeSessionId()} is called to change the session ID - * and retain all session attributes. - * @return the {@link SessionManagementConfigurer} for further customizations - */ - public SessionManagementConfigurer changeSessionId() { - setSessionFixationAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy()); - return SessionManagementConfigurer.this; - } - - /** - * Specifies that no session fixation protection should be enabled. This may be - * useful when utilizing other mechanisms for protecting against session fixation. - * For example, if application container session fixation protection is already in - * use. Otherwise, this option is not recommended. - * @return the {@link SessionManagementConfigurer} for further customizations - */ - public SessionManagementConfigurer none() { - setSessionFixationAuthenticationStrategy(new NullAuthenticatedSessionStrategy()); - return SessionManagementConfigurer.this; - } - - } - - /** - * Allows configuring controlling of multiple sessions. - * - * @author Rob Winch - */ - public final class ConcurrencyControlConfigurer { - - /** - * Controls the maximum number of sessions for a user. The default is to allow any - * number of users. - * @param maximumSessions the maximum number of sessions for a user - * @return the {@link ConcurrencyControlConfigurer} for further customizations - */ - public ConcurrencyControlConfigurer maximumSessions(int maximumSessions) { - SessionManagementConfigurer.this.maximumSessions = maximumSessions; - return this; - } - - /** - * The URL to redirect to if a user tries to access a resource and their session - * has been expired due to too many sessions for the current user. The default is - * to write a simple error message to the response. - * @param expiredUrl the URL to redirect to - * @return the {@link ConcurrencyControlConfigurer} for further customizations - */ - public ConcurrencyControlConfigurer expiredUrl(String expiredUrl) { - SessionManagementConfigurer.this.expiredUrl = expiredUrl; - return this; - } - - /** - * Determines the behaviour when an expired session is detected. - * @param expiredSessionStrategy the {@link SessionInformationExpiredStrategy} to - * use when an expired session is detected. - * @return the {@link ConcurrencyControlConfigurer} for further customizations - */ - public ConcurrencyControlConfigurer expiredSessionStrategy( - SessionInformationExpiredStrategy expiredSessionStrategy) { - SessionManagementConfigurer.this.expiredSessionStrategy = expiredSessionStrategy; - return this; - } - - /** - * If true, prevents a user from authenticating when the - * {@link #maximumSessions(int)} has been reached. Otherwise (default), the user - * who authenticates is allowed access and an existing user's session is expired. - * The user's who's session is forcibly expired is sent to - * {@link #expiredUrl(String)}. The advantage of this approach is if a user - * accidentally does not log out, there is no need for an administrator to - * intervene or wait till their session expires. - * @param maxSessionsPreventsLogin true to have an error at time of - * authentication, else false (default) - * @return the {@link ConcurrencyControlConfigurer} for further customizations - */ - public ConcurrencyControlConfigurer maxSessionsPreventsLogin(boolean maxSessionsPreventsLogin) { - SessionManagementConfigurer.this.maxSessionsPreventsLogin = maxSessionsPreventsLogin; - return this; - } - - /** - * Controls the {@link SessionRegistry} implementation used. The default is - * {@link SessionRegistryImpl} which is an in memory implementation. - * @param sessionRegistry the {@link SessionRegistry} to use - * @return the {@link ConcurrencyControlConfigurer} for further customizations - */ - public ConcurrencyControlConfigurer sessionRegistry(SessionRegistry sessionRegistry) { - SessionManagementConfigurer.this.sessionRegistry = sessionRegistry; - return this; - } - - /** - * Used to chain back to the {@link SessionManagementConfigurer} - * @return the {@link SessionManagementConfigurer} for further customizations - */ - public SessionManagementConfigurer and() { - return SessionManagementConfigurer.this; - } - - private ConcurrencyControlConfigurer() { - } - - } - @Override public void init(H http) { SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class); @@ -703,4 +565,142 @@ public final class SessionManagementConfigurer> } } + /** + * Allows configuring SessionFixation protection + * + * @author Rob Winch + */ + public final class SessionFixationConfigurer { + + /** + * Specifies that a new session should be created, but the session attributes from + * the original {@link HttpSession} should not be retained. + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer newSession() { + SessionFixationProtectionStrategy sessionFixationProtectionStrategy = new SessionFixationProtectionStrategy(); + sessionFixationProtectionStrategy.setMigrateSessionAttributes(false); + setSessionFixationAuthenticationStrategy(sessionFixationProtectionStrategy); + return SessionManagementConfigurer.this; + } + + /** + * Specifies that a new session should be created and the session attributes from + * the original {@link HttpSession} should be retained. + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer migrateSession() { + setSessionFixationAuthenticationStrategy(new SessionFixationProtectionStrategy()); + return SessionManagementConfigurer.this; + } + + /** + * Specifies that the Servlet container-provided session fixation protection + * should be used. When a session authenticates, the Servlet method + * {@code HttpServletRequest#changeSessionId()} is called to change the session ID + * and retain all session attributes. + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer changeSessionId() { + setSessionFixationAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy()); + return SessionManagementConfigurer.this; + } + + /** + * Specifies that no session fixation protection should be enabled. This may be + * useful when utilizing other mechanisms for protecting against session fixation. + * For example, if application container session fixation protection is already in + * use. Otherwise, this option is not recommended. + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer none() { + setSessionFixationAuthenticationStrategy(new NullAuthenticatedSessionStrategy()); + return SessionManagementConfigurer.this; + } + + } + + /** + * Allows configuring controlling of multiple sessions. + * + * @author Rob Winch + */ + public final class ConcurrencyControlConfigurer { + + /** + * Controls the maximum number of sessions for a user. The default is to allow any + * number of users. + * @param maximumSessions the maximum number of sessions for a user + * @return the {@link ConcurrencyControlConfigurer} for further customizations + */ + public ConcurrencyControlConfigurer maximumSessions(int maximumSessions) { + SessionManagementConfigurer.this.maximumSessions = maximumSessions; + return this; + } + + /** + * The URL to redirect to if a user tries to access a resource and their session + * has been expired due to too many sessions for the current user. The default is + * to write a simple error message to the response. + * @param expiredUrl the URL to redirect to + * @return the {@link ConcurrencyControlConfigurer} for further customizations + */ + public ConcurrencyControlConfigurer expiredUrl(String expiredUrl) { + SessionManagementConfigurer.this.expiredUrl = expiredUrl; + return this; + } + + /** + * Determines the behaviour when an expired session is detected. + * @param expiredSessionStrategy the {@link SessionInformationExpiredStrategy} to + * use when an expired session is detected. + * @return the {@link ConcurrencyControlConfigurer} for further customizations + */ + public ConcurrencyControlConfigurer expiredSessionStrategy( + SessionInformationExpiredStrategy expiredSessionStrategy) { + SessionManagementConfigurer.this.expiredSessionStrategy = expiredSessionStrategy; + return this; + } + + /** + * If true, prevents a user from authenticating when the + * {@link #maximumSessions(int)} has been reached. Otherwise (default), the user + * who authenticates is allowed access and an existing user's session is expired. + * The user's who's session is forcibly expired is sent to + * {@link #expiredUrl(String)}. The advantage of this approach is if a user + * accidentally does not log out, there is no need for an administrator to + * intervene or wait till their session expires. + * @param maxSessionsPreventsLogin true to have an error at time of + * authentication, else false (default) + * @return the {@link ConcurrencyControlConfigurer} for further customizations + */ + public ConcurrencyControlConfigurer maxSessionsPreventsLogin(boolean maxSessionsPreventsLogin) { + SessionManagementConfigurer.this.maxSessionsPreventsLogin = maxSessionsPreventsLogin; + return this; + } + + /** + * Controls the {@link SessionRegistry} implementation used. The default is + * {@link SessionRegistryImpl} which is an in memory implementation. + * @param sessionRegistry the {@link SessionRegistry} to use + * @return the {@link ConcurrencyControlConfigurer} for further customizations + */ + public ConcurrencyControlConfigurer sessionRegistry(SessionRegistry sessionRegistry) { + SessionManagementConfigurer.this.sessionRegistry = sessionRegistry; + return this; + } + + /** + * Used to chain back to the {@link SessionManagementConfigurer} + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer and() { + return SessionManagementConfigurer.this; + } + + private ConcurrencyControlConfigurer() { + } + + } + } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java index b9a47da77e..149a7e79ac 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java @@ -114,48 +114,6 @@ public final class UrlAuthorizationConfigurer> return this; } - public final class StandardInterceptUrlRegistry extends - ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { - - /** - * @param context - */ - private StandardInterceptUrlRegistry(ApplicationContext context) { - setApplicationContext(context); - } - - @Override - public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) { - return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns)); - } - - @Override - public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) { - return mvcMatchers(null, patterns); - } - - @Override - protected AuthorizedUrl chainRequestMatchersInternal(List requestMatchers) { - return new AuthorizedUrl(requestMatchers); - } - - /** - * Adds an {@link ObjectPostProcessor} for this class. - * @param objectPostProcessor - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customizations - */ - public StandardInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - addObjectPostProcessor(objectPostProcessor); - return this; - } - - public H and() { - return UrlAuthorizationConfigurer.this.and(); - } - - } - /** * Creates the default {@link AccessDecisionVoter} instances used if an * {@link AccessDecisionManager} was not specified. @@ -234,6 +192,48 @@ public final class UrlAuthorizationConfigurer> return authorities; } + public final class StandardInterceptUrlRegistry extends + ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { + + /** + * @param context + */ + private StandardInterceptUrlRegistry(ApplicationContext context) { + setApplicationContext(context); + } + + @Override + public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) { + return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns)); + } + + @Override + public MvcMatchersAuthorizedUrl mvcMatchers(String... patterns) { + return mvcMatchers(null, patterns); + } + + @Override + protected AuthorizedUrl chainRequestMatchersInternal(List requestMatchers) { + return new AuthorizedUrl(requestMatchers); + } + + /** + * Adds an {@link ObjectPostProcessor} for this class. + * @param objectPostProcessor + * @return the {@link ExpressionUrlAuthorizationConfigurer} for further + * customizations + */ + public StandardInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { + addObjectPostProcessor(objectPostProcessor); + return this; + } + + public H and() { + return UrlAuthorizationConfigurer.this.and(); + } + + } + /** * An {@link AuthorizedUrl} that allows optionally configuring the * {@link MvcRequestMatcher#setMethod(HttpMethod)} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java index 64e9205359..96fe913fc6 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java @@ -151,6 +151,16 @@ public final class OAuth2ClientConfigurer> return this; } + @Override + public void init(B builder) { + this.authorizationCodeGrantConfigurer.init(builder); + } + + @Override + public void configure(B builder) { + this.authorizationCodeGrantConfigurer.configure(builder); + } + /** * Configuration options for the OAuth 2.0 Authorization Code Grant. */ @@ -281,14 +291,4 @@ public final class OAuth2ClientConfigurer> } - @Override - public void init(B builder) { - this.authorizationCodeGrantConfigurer.init(builder); - } - - @Override - public void configure(B builder) { - this.authorizationCodeGrantConfigurer.configure(builder); - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 01c8d1625d..9944dedfa3 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -221,69 +221,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Configuration options for the Authorization Server's Authorization Endpoint. - */ - public final class AuthorizationEndpointConfig { - - private String authorizationRequestBaseUri; - - private OAuth2AuthorizationRequestResolver authorizationRequestResolver; - - private AuthorizationRequestRepository authorizationRequestRepository; - - private AuthorizationEndpointConfig() { - } - - /** - * Sets the base {@code URI} used for authorization requests. - * @param authorizationRequestBaseUri the base {@code URI} used for authorization - * requests - * @return the {@link AuthorizationEndpointConfig} for further configuration - */ - public AuthorizationEndpointConfig baseUri(String authorizationRequestBaseUri) { - Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty"); - this.authorizationRequestBaseUri = authorizationRequestBaseUri; - return this; - } - - /** - * Sets the resolver used for resolving {@link OAuth2AuthorizationRequest}'s. - * @param authorizationRequestResolver the resolver used for resolving - * {@link OAuth2AuthorizationRequest}'s - * @return the {@link AuthorizationEndpointConfig} for further configuration - * @since 5.1 - */ - public AuthorizationEndpointConfig authorizationRequestResolver( - OAuth2AuthorizationRequestResolver authorizationRequestResolver) { - Assert.notNull(authorizationRequestResolver, "authorizationRequestResolver cannot be null"); - this.authorizationRequestResolver = authorizationRequestResolver; - return this; - } - - /** - * Sets the repository used for storing {@link OAuth2AuthorizationRequest}'s. - * @param authorizationRequestRepository the repository used for storing - * {@link OAuth2AuthorizationRequest}'s - * @return the {@link AuthorizationEndpointConfig} for further configuration - */ - public AuthorizationEndpointConfig authorizationRequestRepository( - AuthorizationRequestRepository authorizationRequestRepository) { - Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null"); - this.authorizationRequestRepository = authorizationRequestRepository; - return this; - } - - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - */ - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - - } - /** * Returns the {@link TokenEndpointConfig} for configuring the Authorization Server's * Token Endpoint. @@ -305,41 +242,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Configuration options for the Authorization Server's Token Endpoint. - */ - public final class TokenEndpointConfig { - - private OAuth2AccessTokenResponseClient accessTokenResponseClient; - - private TokenEndpointConfig() { - } - - /** - * Sets the client used for requesting the access token credential from the Token - * Endpoint. - * @param accessTokenResponseClient the client used for requesting the access - * token credential from the Token Endpoint - * @return the {@link TokenEndpointConfig} for further configuration - */ - public TokenEndpointConfig accessTokenResponseClient( - OAuth2AccessTokenResponseClient accessTokenResponseClient) { - - Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null"); - this.accessTokenResponseClient = accessTokenResponseClient; - return this; - } - - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - */ - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - - } - /** * Returns the {@link RedirectionEndpointConfig} for configuring the Client's * Redirection Endpoint. @@ -361,38 +263,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Configuration options for the Client's Redirection Endpoint. - */ - public final class RedirectionEndpointConfig { - - private String authorizationResponseBaseUri; - - private RedirectionEndpointConfig() { - } - - /** - * Sets the {@code URI} where the authorization response will be processed. - * @param authorizationResponseBaseUri the {@code URI} where the authorization - * response will be processed - * @return the {@link RedirectionEndpointConfig} for further configuration - */ - public RedirectionEndpointConfig baseUri(String authorizationResponseBaseUri) { - Assert.hasText(authorizationResponseBaseUri, "authorizationResponseBaseUri cannot be empty"); - this.authorizationResponseBaseUri = authorizationResponseBaseUri; - return this; - } - - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - */ - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - - } - /** * Returns the {@link UserInfoEndpointConfig} for configuring the Authorization * Server's UserInfo Endpoint. @@ -413,87 +283,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Configuration options for the Authorization Server's UserInfo Endpoint. - */ - public final class UserInfoEndpointConfig { - - private OAuth2UserService userService; - - private OAuth2UserService oidcUserService; - - private Map> customUserTypes = new HashMap<>(); - - private UserInfoEndpointConfig() { - } - - /** - * Sets the OAuth 2.0 service used for obtaining the user attributes of the - * End-User from the UserInfo Endpoint. - * @param userService the OAuth 2.0 service used for obtaining the user attributes - * of the End-User from the UserInfo Endpoint - * @return the {@link UserInfoEndpointConfig} for further configuration - */ - public UserInfoEndpointConfig userService(OAuth2UserService userService) { - Assert.notNull(userService, "userService cannot be null"); - this.userService = userService; - return this; - } - - /** - * Sets the OpenID Connect 1.0 service used for obtaining the user attributes of - * the End-User from the UserInfo Endpoint. - * @param oidcUserService the OpenID Connect 1.0 service used for obtaining the - * user attributes of the End-User from the UserInfo Endpoint - * @return the {@link UserInfoEndpointConfig} for further configuration - */ - public UserInfoEndpointConfig oidcUserService(OAuth2UserService oidcUserService) { - Assert.notNull(oidcUserService, "oidcUserService cannot be null"); - this.oidcUserService = oidcUserService; - return this; - } - - /** - * Sets a custom {@link OAuth2User} type and associates it to the provided client - * {@link ClientRegistration#getRegistrationId() registration identifier}. - * @deprecated See {@link CustomUserTypesOAuth2UserService} for alternative usage. - * @param customUserType a custom {@link OAuth2User} type - * @param clientRegistrationId the client registration identifier - * @return the {@link UserInfoEndpointConfig} for further configuration - */ - @Deprecated - public UserInfoEndpointConfig customUserType(Class customUserType, - String clientRegistrationId) { - Assert.notNull(customUserType, "customUserType cannot be null"); - Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty"); - this.customUserTypes.put(clientRegistrationId, customUserType); - return this; - } - - /** - * Sets the {@link GrantedAuthoritiesMapper} used for mapping - * {@link OAuth2User#getAuthorities()}. - * @param userAuthoritiesMapper the {@link GrantedAuthoritiesMapper} used for - * mapping the user's authorities - * @return the {@link UserInfoEndpointConfig} for further configuration - */ - public UserInfoEndpointConfig userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) { - Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null"); - OAuth2LoginConfigurer.this.getBuilder().setSharedObject(GrantedAuthoritiesMapper.class, - userAuthoritiesMapper); - return this; - } - - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - */ - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - - } - @Override public void init(B http) throws Exception { OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter( @@ -740,6 +529,217 @@ public final class OAuth2LoginConfigurer> return loginEntryPoint; } + /** + * Configuration options for the Authorization Server's Authorization Endpoint. + */ + public final class AuthorizationEndpointConfig { + + private String authorizationRequestBaseUri; + + private OAuth2AuthorizationRequestResolver authorizationRequestResolver; + + private AuthorizationRequestRepository authorizationRequestRepository; + + private AuthorizationEndpointConfig() { + } + + /** + * Sets the base {@code URI} used for authorization requests. + * @param authorizationRequestBaseUri the base {@code URI} used for authorization + * requests + * @return the {@link AuthorizationEndpointConfig} for further configuration + */ + public AuthorizationEndpointConfig baseUri(String authorizationRequestBaseUri) { + Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty"); + this.authorizationRequestBaseUri = authorizationRequestBaseUri; + return this; + } + + /** + * Sets the resolver used for resolving {@link OAuth2AuthorizationRequest}'s. + * @param authorizationRequestResolver the resolver used for resolving + * {@link OAuth2AuthorizationRequest}'s + * @return the {@link AuthorizationEndpointConfig} for further configuration + * @since 5.1 + */ + public AuthorizationEndpointConfig authorizationRequestResolver( + OAuth2AuthorizationRequestResolver authorizationRequestResolver) { + Assert.notNull(authorizationRequestResolver, "authorizationRequestResolver cannot be null"); + this.authorizationRequestResolver = authorizationRequestResolver; + return this; + } + + /** + * Sets the repository used for storing {@link OAuth2AuthorizationRequest}'s. + * @param authorizationRequestRepository the repository used for storing + * {@link OAuth2AuthorizationRequest}'s + * @return the {@link AuthorizationEndpointConfig} for further configuration + */ + public AuthorizationEndpointConfig authorizationRequestRepository( + AuthorizationRequestRepository authorizationRequestRepository) { + Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null"); + this.authorizationRequestRepository = authorizationRequestRepository; + return this; + } + + /** + * Returns the {@link OAuth2LoginConfigurer} for further configuration. + * @return the {@link OAuth2LoginConfigurer} + */ + public OAuth2LoginConfigurer and() { + return OAuth2LoginConfigurer.this; + } + + } + + /** + * Configuration options for the Authorization Server's Token Endpoint. + */ + public final class TokenEndpointConfig { + + private OAuth2AccessTokenResponseClient accessTokenResponseClient; + + private TokenEndpointConfig() { + } + + /** + * Sets the client used for requesting the access token credential from the Token + * Endpoint. + * @param accessTokenResponseClient the client used for requesting the access + * token credential from the Token Endpoint + * @return the {@link TokenEndpointConfig} for further configuration + */ + public TokenEndpointConfig accessTokenResponseClient( + OAuth2AccessTokenResponseClient accessTokenResponseClient) { + + Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null"); + this.accessTokenResponseClient = accessTokenResponseClient; + return this; + } + + /** + * Returns the {@link OAuth2LoginConfigurer} for further configuration. + * @return the {@link OAuth2LoginConfigurer} + */ + public OAuth2LoginConfigurer and() { + return OAuth2LoginConfigurer.this; + } + + } + + /** + * Configuration options for the Client's Redirection Endpoint. + */ + public final class RedirectionEndpointConfig { + + private String authorizationResponseBaseUri; + + private RedirectionEndpointConfig() { + } + + /** + * Sets the {@code URI} where the authorization response will be processed. + * @param authorizationResponseBaseUri the {@code URI} where the authorization + * response will be processed + * @return the {@link RedirectionEndpointConfig} for further configuration + */ + public RedirectionEndpointConfig baseUri(String authorizationResponseBaseUri) { + Assert.hasText(authorizationResponseBaseUri, "authorizationResponseBaseUri cannot be empty"); + this.authorizationResponseBaseUri = authorizationResponseBaseUri; + return this; + } + + /** + * Returns the {@link OAuth2LoginConfigurer} for further configuration. + * @return the {@link OAuth2LoginConfigurer} + */ + public OAuth2LoginConfigurer and() { + return OAuth2LoginConfigurer.this; + } + + } + + /** + * Configuration options for the Authorization Server's UserInfo Endpoint. + */ + public final class UserInfoEndpointConfig { + + private OAuth2UserService userService; + + private OAuth2UserService oidcUserService; + + private Map> customUserTypes = new HashMap<>(); + + private UserInfoEndpointConfig() { + } + + /** + * Sets the OAuth 2.0 service used for obtaining the user attributes of the + * End-User from the UserInfo Endpoint. + * @param userService the OAuth 2.0 service used for obtaining the user attributes + * of the End-User from the UserInfo Endpoint + * @return the {@link UserInfoEndpointConfig} for further configuration + */ + public UserInfoEndpointConfig userService(OAuth2UserService userService) { + Assert.notNull(userService, "userService cannot be null"); + this.userService = userService; + return this; + } + + /** + * Sets the OpenID Connect 1.0 service used for obtaining the user attributes of + * the End-User from the UserInfo Endpoint. + * @param oidcUserService the OpenID Connect 1.0 service used for obtaining the + * user attributes of the End-User from the UserInfo Endpoint + * @return the {@link UserInfoEndpointConfig} for further configuration + */ + public UserInfoEndpointConfig oidcUserService(OAuth2UserService oidcUserService) { + Assert.notNull(oidcUserService, "oidcUserService cannot be null"); + this.oidcUserService = oidcUserService; + return this; + } + + /** + * Sets a custom {@link OAuth2User} type and associates it to the provided client + * {@link ClientRegistration#getRegistrationId() registration identifier}. + * @deprecated See {@link CustomUserTypesOAuth2UserService} for alternative usage. + * @param customUserType a custom {@link OAuth2User} type + * @param clientRegistrationId the client registration identifier + * @return the {@link UserInfoEndpointConfig} for further configuration + */ + @Deprecated + public UserInfoEndpointConfig customUserType(Class customUserType, + String clientRegistrationId) { + Assert.notNull(customUserType, "customUserType cannot be null"); + Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty"); + this.customUserTypes.put(clientRegistrationId, customUserType); + return this; + } + + /** + * Sets the {@link GrantedAuthoritiesMapper} used for mapping + * {@link OAuth2User#getAuthorities()}. + * @param userAuthoritiesMapper the {@link GrantedAuthoritiesMapper} used for + * mapping the user's authorities + * @return the {@link UserInfoEndpointConfig} for further configuration + */ + public UserInfoEndpointConfig userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) { + Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null"); + OAuth2LoginConfigurer.this.getBuilder().setSharedObject(GrantedAuthoritiesMapper.class, + userAuthoritiesMapper); + return this; + } + + /** + * Returns the {@link OAuth2LoginConfigurer} for further configuration. + * @return the {@link OAuth2LoginConfigurer} + */ + public OAuth2LoginConfigurer and() { + return OAuth2LoginConfigurer.this; + } + + } + private static class OidcAuthenticationRequestChecker implements AuthenticationProvider { @Override diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java index f22c68ab83..9b45741903 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java @@ -277,6 +277,70 @@ public final class OAuth2ResourceServerConfigurer exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class); + if (exceptionHandling == null) { + return; + } + + exceptionHandling.defaultAccessDeniedHandlerFor(this.accessDeniedHandler, this.requestMatcher); + } + + private void registerDefaultEntryPoint(H http) { + ExceptionHandlingConfigurer exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class); + if (exceptionHandling == null) { + return; + } + + exceptionHandling.defaultAuthenticationEntryPointFor(this.authenticationEntryPoint, this.requestMatcher); + } + + private void registerDefaultCsrfOverride(H http) { + CsrfConfigurer csrf = http.getConfigurer(CsrfConfigurer.class); + if (csrf == null) { + return; + } + + csrf.ignoringRequestMatchers(this.requestMatcher); + } + + AuthenticationProvider getAuthenticationProvider() { + if (this.jwtConfigurer != null) { + return this.jwtConfigurer.getAuthenticationProvider(); + } + + if (this.opaqueTokenConfigurer != null) { + return this.opaqueTokenConfigurer.getAuthenticationProvider(); + } + + return null; + } + + AuthenticationManager getAuthenticationManager(H http) { + if (this.jwtConfigurer != null) { + return this.jwtConfigurer.getAuthenticationManager(http); + } + + if (this.opaqueTokenConfigurer != null) { + return this.opaqueTokenConfigurer.getAuthenticationManager(http); + } + + return http.getSharedObject(AuthenticationManager.class); + } + + BearerTokenResolver getBearerTokenResolver() { + if (this.bearerTokenResolver == null) { + if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) { + this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); + } + else { + this.bearerTokenResolver = new DefaultBearerTokenResolver(); + } + } + + return this.bearerTokenResolver; + } + public class JwtConfigurer { private final ApplicationContext context; @@ -435,70 +499,6 @@ public final class OAuth2ResourceServerConfigurer exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class); - if (exceptionHandling == null) { - return; - } - - exceptionHandling.defaultAccessDeniedHandlerFor(this.accessDeniedHandler, this.requestMatcher); - } - - private void registerDefaultEntryPoint(H http) { - ExceptionHandlingConfigurer exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class); - if (exceptionHandling == null) { - return; - } - - exceptionHandling.defaultAuthenticationEntryPointFor(this.authenticationEntryPoint, this.requestMatcher); - } - - private void registerDefaultCsrfOverride(H http) { - CsrfConfigurer csrf = http.getConfigurer(CsrfConfigurer.class); - if (csrf == null) { - return; - } - - csrf.ignoringRequestMatchers(this.requestMatcher); - } - - AuthenticationProvider getAuthenticationProvider() { - if (this.jwtConfigurer != null) { - return this.jwtConfigurer.getAuthenticationProvider(); - } - - if (this.opaqueTokenConfigurer != null) { - return this.opaqueTokenConfigurer.getAuthenticationProvider(); - } - - return null; - } - - AuthenticationManager getAuthenticationManager(H http) { - if (this.jwtConfigurer != null) { - return this.jwtConfigurer.getAuthenticationManager(http); - } - - if (this.opaqueTokenConfigurer != null) { - return this.opaqueTokenConfigurer.getAuthenticationManager(http); - } - - return http.getSharedObject(AuthenticationManager.class); - } - - BearerTokenResolver getBearerTokenResolver() { - if (this.bearerTokenResolver == null) { - if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) { - this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); - } - else { - this.bearerTokenResolver = new DefaultBearerTokenResolver(); - } - } - - return this.bearerTokenResolver; - } - private static final class BearerTokenRequestMatcher implements RequestMatcher { private BearerTokenResolver bearerTokenResolver; diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java index 4507c9d845..ec3a1ba2b6 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/messaging/MessageSecurityMetadataSourceRegistry.java @@ -247,6 +247,29 @@ public class MessageSecurityMetadataSourceRegistry { return !this.matcherToExpression.isEmpty(); } + private static String hasAnyRole(String... authorities) { + String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_"); + return "hasAnyRole('ROLE_" + anyAuthorities + "')"; + } + + private static String hasRole(String role) { + Assert.notNull(role, "role cannot be null"); + if (role.startsWith("ROLE_")) { + throw new IllegalArgumentException( + "role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'"); + } + return "hasRole('ROLE_" + role + "')"; + } + + private static String hasAuthority(String authority) { + return "hasAuthority('" + authority + "')"; + } + + private static String hasAnyAuthority(String... authorities) { + String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','"); + return "hasAnyAuthority('" + anyAuthorities + "')"; + } + /** * Represents the security constraint to be applied to the {@link MessageMatcher} * instances. @@ -386,29 +409,6 @@ public class MessageSecurityMetadataSourceRegistry { } - private static String hasAnyRole(String... authorities) { - String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_"); - return "hasAnyRole('ROLE_" + anyAuthorities + "')"; - } - - private static String hasRole(String role) { - Assert.notNull(role, "role cannot be null"); - if (role.startsWith("ROLE_")) { - throw new IllegalArgumentException( - "role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'"); - } - return "hasRole('ROLE_" + role + "')"; - } - - private static String hasAuthority(String authority) { - return "hasAuthority('" + authority + "')"; - } - - private static String hasAnyAuthority(String... authorities) { - String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','"); - return "hasAnyAuthority('" + anyAuthorities + "')"; - } - private final static class PreBuiltMatcherBuilder implements MatcherBuilder { private MessageMatcher matcher; diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java index 25bec814d6..4e2334e98e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java @@ -186,25 +186,6 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends A protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { } - private static class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry { - - @Override - public MessageSecurityMetadataSource createMetadataSource() { - return super.createMetadataSource(); - } - - @Override - protected boolean containsMapping() { - return super.containsMapping(); - } - - @Override - protected boolean isSimpDestPathMatcherConfigured() { - return super.isSimpDestPathMatcherConfigured(); - } - - } - @Autowired public void setApplicationContext(ApplicationContext context) { this.context = context; @@ -283,4 +264,23 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends A } } + private static class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry { + + @Override + public MessageSecurityMetadataSource createMetadataSource() { + return super.createMetadataSource(); + } + + @Override + protected boolean containsMapping() { + return super.containsMapping(); + } + + @Override + protected boolean isSimpDestPathMatcherConfigured() { + return super.isSimpDestPathMatcherConfigured(); + } + + } + } diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index 759228c707..5d87cbfa9e 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -296,6 +296,9 @@ public class ServerHttpSecurity { private AnonymousSpec anonymous; + protected ServerHttpSecurity() { + } + /** * The ServerExchangeMatcher that determines which requests apply to this HttpSecurity * instance. @@ -624,70 +627,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures CORS support within Spring Security. This ensures that the - * {@link CorsWebFilter} is place in the correct order. - */ - public final class CorsSpec { - - private CorsWebFilter corsFilter; - - private CorsSpec() { - } - - /** - * Configures the {@link CorsConfigurationSource} to be used - * @param source the source to use - * @return the {@link CorsSpec} for additional configuration - */ - public CorsSpec configurationSource(CorsConfigurationSource source) { - this.corsFilter = new CorsWebFilter(source); - return this; - } - - /** - * Disables CORS support within Spring Security. - * @return the {@link ServerHttpSecurity} to continue configuring - */ - public ServerHttpSecurity disable() { - ServerHttpSecurity.this.cors = null; - return ServerHttpSecurity.this; - } - - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - */ - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - - protected void configure(ServerHttpSecurity http) { - CorsWebFilter corsFilter = getCorsFilter(); - if (corsFilter != null) { - http.addFilterAt(this.corsFilter, SecurityWebFiltersOrder.CORS); - } - } - - private CorsWebFilter getCorsFilter() { - if (this.corsFilter != null) { - return this.corsFilter; - } - - CorsConfigurationSource source = getBeanOrNull(CorsConfigurationSource.class); - if (source == null) { - return null; - } - CorsProcessor processor = getBeanOrNull(CorsProcessor.class); - if (processor == null) { - processor = new DefaultCorsProcessor(); - } - this.corsFilter = new CorsWebFilter(source, processor); - return this.corsFilter; - } - - } - /** * Configures HTTP Basic authentication. An example configuration is provided below: * @@ -867,67 +806,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures X509 authentication - * - * @author Alexey Nesterov - * @since 5.2 - * @see #x509() - */ - public final class X509Spec { - - private X509PrincipalExtractor principalExtractor; - - private ReactiveAuthenticationManager authenticationManager; - - private X509Spec() { - } - - public X509Spec principalExtractor(X509PrincipalExtractor principalExtractor) { - this.principalExtractor = principalExtractor; - return this; - } - - public X509Spec authenticationManager(ReactiveAuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - return this; - } - - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - - protected void configure(ServerHttpSecurity http) { - ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); - X509PrincipalExtractor principalExtractor = getPrincipalExtractor(); - - AuthenticationWebFilter filter = new AuthenticationWebFilter(authenticationManager); - filter.setServerAuthenticationConverter(new ServerX509AuthenticationConverter(principalExtractor)); - http.addFilterAt(filter, SecurityWebFiltersOrder.AUTHENTICATION); - } - - private X509PrincipalExtractor getPrincipalExtractor() { - if (this.principalExtractor != null) { - return this.principalExtractor; - } - - return new SubjectDnX509PrincipalExtractor(); - } - - private ReactiveAuthenticationManager getAuthenticationManager() { - if (this.authenticationManager != null) { - return this.authenticationManager; - } - - ReactiveUserDetailsService userDetailsService = getBean(ReactiveUserDetailsService.class); - ReactivePreAuthenticatedAuthenticationManager authenticationManager = new ReactivePreAuthenticatedAuthenticationManager( - userDetailsService); - - return authenticationManager; - } - - } - /** * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 * Provider. @@ -981,408 +859,6 @@ public class ServerHttpSecurity { return this; } - public final class OAuth2LoginSpec { - - private ReactiveClientRegistrationRepository clientRegistrationRepository; - - private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; - - private ServerAuthorizationRequestRepository authorizationRequestRepository; - - private ReactiveAuthenticationManager authenticationManager; - - private ServerSecurityContextRepository securityContextRepository; - - private ServerAuthenticationConverter authenticationConverter; - - private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver; - - private ServerWebExchangeMatcher authenticationMatcher; - - private ServerAuthenticationSuccessHandler authenticationSuccessHandler; - - private ServerAuthenticationFailureHandler authenticationFailureHandler; - - private OAuth2LoginSpec() { - } - - /** - * Configures the {@link ReactiveAuthenticationManager} to use. The default is - * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} - * @param authenticationManager the manager to use - * @return the {@link OAuth2LoginSpec} to customize - */ - public OAuth2LoginSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - return this; - } - - /** - * The {@link ServerSecurityContextRepository} used to save the - * {@code Authentication}. Defaults to - * {@link WebSessionServerSecurityContextRepository}. - * @param securityContextRepository the repository to use - * @return the {@link OAuth2LoginSpec} to continue configuring - * @since 5.2 - */ - public OAuth2LoginSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) { - this.securityContextRepository = securityContextRepository; - return this; - } - - /** - * The {@link ServerAuthenticationSuccessHandler} used after authentication - * success. Defaults to {@link RedirectServerAuthenticationSuccessHandler} - * redirecting to "/". - * @param authenticationSuccessHandler the success handler to use - * @return the {@link OAuth2LoginSpec} to customize - * @since 5.2 - */ - public OAuth2LoginSpec authenticationSuccessHandler( - ServerAuthenticationSuccessHandler authenticationSuccessHandler) { - Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null"); - this.authenticationSuccessHandler = authenticationSuccessHandler; - return this; - } - - /** - * The {@link ServerAuthenticationFailureHandler} used after authentication - * failure. Defaults to {@link RedirectServerAuthenticationFailureHandler} - * redirecting to "/login?error". - * @param authenticationFailureHandler the failure handler to use - * @return the {@link OAuth2LoginSpec} to customize - * @since 5.2 - */ - public OAuth2LoginSpec authenticationFailureHandler( - ServerAuthenticationFailureHandler authenticationFailureHandler) { - Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null"); - this.authenticationFailureHandler = authenticationFailureHandler; - return this; - } - - /** - * Gets the {@link ReactiveAuthenticationManager} to use. First tries an - * explicitly configured manager, and defaults to - * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} - * @return the {@link ReactiveAuthenticationManager} to use - */ - private ReactiveAuthenticationManager getAuthenticationManager() { - if (this.authenticationManager == null) { - this.authenticationManager = createDefault(); - } - return this.authenticationManager; - } - - private ReactiveAuthenticationManager createDefault() { - ReactiveOAuth2AccessTokenResponseClient client = getAccessTokenResponseClient(); - OAuth2LoginReactiveAuthenticationManager oauth2Manager = new OAuth2LoginReactiveAuthenticationManager( - client, getOauth2UserService()); - GrantedAuthoritiesMapper authoritiesMapper = getBeanOrNull(GrantedAuthoritiesMapper.class); - if (authoritiesMapper != null) { - oauth2Manager.setAuthoritiesMapper(authoritiesMapper); - } - boolean oidcAuthenticationProviderEnabled = ClassUtils - .isPresent("org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader()); - if (oidcAuthenticationProviderEnabled) { - OidcAuthorizationCodeReactiveAuthenticationManager oidc = new OidcAuthorizationCodeReactiveAuthenticationManager( - client, getOidcUserService()); - ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveJwtDecoderFactory.class, - ClientRegistration.class); - ReactiveJwtDecoderFactory jwtDecoderFactory = getBeanOrNull(type); - if (jwtDecoderFactory != null) { - oidc.setJwtDecoderFactory(jwtDecoderFactory); - } - if (authoritiesMapper != null) { - oidc.setAuthoritiesMapper(authoritiesMapper); - } - return new DelegatingReactiveAuthenticationManager(oidc, oauth2Manager); - } - return oauth2Manager; - } - - /** - * Sets the converter to use - * @param authenticationConverter the converter to use - * @return the {@link OAuth2LoginSpec} to customize - */ - public OAuth2LoginSpec authenticationConverter(ServerAuthenticationConverter authenticationConverter) { - this.authenticationConverter = authenticationConverter; - return this; - } - - private ServerAuthenticationConverter getAuthenticationConverter( - ReactiveClientRegistrationRepository clientRegistrationRepository) { - if (this.authenticationConverter == null) { - ServerOAuth2AuthorizationCodeAuthenticationTokenConverter delegate = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter( - clientRegistrationRepository); - delegate.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); - ServerAuthenticationConverter authenticationConverter = exchange -> delegate.convert(exchange) - .onErrorMap(OAuth2AuthorizationException.class, - e -> new OAuth2AuthenticationException(e.getError(), e.getError().toString())); - this.authenticationConverter = authenticationConverter; - return authenticationConverter; - } - return this.authenticationConverter; - } - - public OAuth2LoginSpec clientRegistrationRepository( - ReactiveClientRegistrationRepository clientRegistrationRepository) { - this.clientRegistrationRepository = clientRegistrationRepository; - return this; - } - - public OAuth2LoginSpec authorizedClientService(ReactiveOAuth2AuthorizedClientService authorizedClientService) { - this.authorizedClientRepository = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository( - authorizedClientService); - return this; - } - - public OAuth2LoginSpec authorizedClientRepository( - ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { - this.authorizedClientRepository = authorizedClientRepository; - return this; - } - - /** - * Sets the repository to use for storing {@link OAuth2AuthorizationRequest}'s. - * @param authorizationRequestRepository the repository to use for storing - * {@link OAuth2AuthorizationRequest}'s - * @return the {@link OAuth2LoginSpec} for further configuration - * @since 5.2 - */ - public OAuth2LoginSpec authorizationRequestRepository( - ServerAuthorizationRequestRepository authorizationRequestRepository) { - this.authorizationRequestRepository = authorizationRequestRepository; - return this; - } - - /** - * Sets the resolver used for resolving {@link OAuth2AuthorizationRequest}'s. - * @param authorizationRequestResolver the resolver used for resolving - * {@link OAuth2AuthorizationRequest}'s - * @return the {@link OAuth2LoginSpec} for further configuration - * @since 5.2 - */ - public OAuth2LoginSpec authorizationRequestResolver( - ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) { - this.authorizationRequestResolver = authorizationRequestResolver; - return this; - } - - /** - * Sets the {@link ServerWebExchangeMatcher matcher} used for determining if the - * request is an authentication request. - * @param authenticationMatcher the {@link ServerWebExchangeMatcher matcher} used - * for determining if the request is an authentication request - * @return the {@link OAuth2LoginSpec} for further configuration - * @since 5.2 - */ - public OAuth2LoginSpec authenticationMatcher(ServerWebExchangeMatcher authenticationMatcher) { - this.authenticationMatcher = authenticationMatcher; - return this; - } - - private ServerWebExchangeMatcher getAuthenticationMatcher() { - if (this.authenticationMatcher == null) { - this.authenticationMatcher = createAttemptAuthenticationRequestMatcher(); - } - return this.authenticationMatcher; - } - - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - */ - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - - protected void configure(ServerHttpSecurity http) { - ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); - ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); - OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = getRedirectWebFilter(); - ServerAuthorizationRequestRepository authorizationRequestRepository = getAuthorizationRequestRepository(); - oauthRedirectFilter.setAuthorizationRequestRepository(authorizationRequestRepository); - oauthRedirectFilter.setRequestCache(http.requestCache.requestCache); - - ReactiveAuthenticationManager manager = getAuthenticationManager(); - - AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager, - authorizedClientRepository); - authenticationFilter.setRequiresAuthenticationMatcher(getAuthenticationMatcher()); - authenticationFilter - .setServerAuthenticationConverter(getAuthenticationConverter(clientRegistrationRepository)); - - authenticationFilter.setAuthenticationSuccessHandler(getAuthenticationSuccessHandler(http)); - authenticationFilter.setAuthenticationFailureHandler(getAuthenticationFailureHandler()); - authenticationFilter.setSecurityContextRepository(this.securityContextRepository); - - setDefaultEntryPoints(http); - - http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); - http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION); - } - - private void setDefaultEntryPoints(ServerHttpSecurity http) { - String defaultLoginPage = "/login"; - Map 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(); - handler.setRequestCache(http.requestCache.requestCache); - this.authenticationSuccessHandler = handler; - } - return this.authenticationSuccessHandler; - } - - private ServerAuthenticationFailureHandler getAuthenticationFailureHandler() { - if (this.authenticationFailureHandler == null) { - this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler("/login?error"); - } - return this.authenticationFailureHandler; - } - - private ServerWebExchangeMatcher createAttemptAuthenticationRequestMatcher() { - return new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}"); - } - - private ReactiveOAuth2UserService getOidcUserService() { - ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, - OidcUserRequest.class, OidcUser.class); - ReactiveOAuth2UserService bean = getBeanOrNull(type); - if (bean == null) { - return new OidcReactiveOAuth2UserService(); - } - - return bean; - } - - private ReactiveOAuth2UserService getOauth2UserService() { - ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, - OAuth2UserRequest.class, OAuth2User.class); - ReactiveOAuth2UserService bean = getBeanOrNull(type); - if (bean == null) { - return new DefaultReactiveOAuth2UserService(); - } - - return bean; - } - - private Map getLinks() { - Iterable registrations = getBeanOrNull( - ResolvableType.forClassWithGenerics(Iterable.class, ClientRegistration.class)); - if (registrations == null) { - return Collections.emptyMap(); - } - Map result = new HashMap<>(); - registrations.iterator().forEachRemaining( - r -> result.put("/oauth2/authorization/" + r.getRegistrationId(), r.getClientName())); - return result; - } - - private ReactiveOAuth2AccessTokenResponseClient getAccessTokenResponseClient() { - ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2AccessTokenResponseClient.class, - OAuth2AuthorizationCodeGrantRequest.class); - ReactiveOAuth2AccessTokenResponseClient bean = getBeanOrNull(type); - if (bean == null) { - return new WebClientReactiveAuthorizationCodeTokenResponseClient(); - } - return bean; - } - - private ReactiveClientRegistrationRepository getClientRegistrationRepository() { - if (this.clientRegistrationRepository == null) { - this.clientRegistrationRepository = getBeanOrNull(ReactiveClientRegistrationRepository.class); - } - return this.clientRegistrationRepository; - } - - private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() { - OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter; - if (this.authorizationRequestResolver == null) { - oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( - getClientRegistrationRepository()); - } - else { - oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( - this.authorizationRequestResolver); - } - return oauthRedirectFilter; - } - - private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() { - ServerOAuth2AuthorizedClientRepository result = this.authorizedClientRepository; - if (result == null) { - result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class); - } - if (result == null) { - ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService(); - if (authorizedClientService != null) { - result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService); - } - } - return result; - } - - private ServerAuthorizationRequestRepository getAuthorizationRequestRepository() { - if (this.authorizationRequestRepository == null) { - this.authorizationRequestRepository = new WebSessionOAuth2ServerAuthorizationRequestRepository(); - } - return this.authorizationRequestRepository; - } - - private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() { - ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class); - if (service == null) { - service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository()); - } - return service; - } - - } - /** * Configures the OAuth2 client. * @@ -1434,172 +910,6 @@ public class ServerHttpSecurity { return this; } - public final class OAuth2ClientSpec { - - private ReactiveClientRegistrationRepository clientRegistrationRepository; - - private ServerAuthenticationConverter authenticationConverter; - - private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; - - private ReactiveAuthenticationManager authenticationManager; - - private ServerAuthorizationRequestRepository authorizationRequestRepository; - - private OAuth2ClientSpec() { - } - - /** - * Sets the converter to use - * @param authenticationConverter the converter to use - * @return the {@link OAuth2ClientSpec} to customize - */ - public OAuth2ClientSpec authenticationConverter(ServerAuthenticationConverter authenticationConverter) { - this.authenticationConverter = authenticationConverter; - return this; - } - - private ServerAuthenticationConverter getAuthenticationConverter() { - if (this.authenticationConverter == null) { - ServerOAuth2AuthorizationCodeAuthenticationTokenConverter authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter( - getClientRegistrationRepository()); - authenticationConverter.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); - this.authenticationConverter = authenticationConverter; - } - return this.authenticationConverter; - } - - /** - * Configures the {@link ReactiveAuthenticationManager} to use. The default is - * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} - * @param authenticationManager the manager to use - * @return the {@link OAuth2ClientSpec} to customize - */ - public OAuth2ClientSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { - this.authenticationManager = authenticationManager; - return this; - } - - /** - * Gets the {@link ReactiveAuthenticationManager} to use. First tries an - * explicitly configured manager, and defaults to - * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} - * @return the {@link ReactiveAuthenticationManager} to use - */ - private ReactiveAuthenticationManager getAuthenticationManager() { - if (this.authenticationManager == null) { - this.authenticationManager = new OAuth2AuthorizationCodeReactiveAuthenticationManager( - new WebClientReactiveAuthorizationCodeTokenResponseClient()); - } - return this.authenticationManager; - } - - /** - * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look - * the value up as a Bean. - * @param clientRegistrationRepository the repository to use - * @return the {@link OAuth2ClientSpec} to customize - */ - public OAuth2ClientSpec clientRegistrationRepository( - ReactiveClientRegistrationRepository clientRegistrationRepository) { - this.clientRegistrationRepository = clientRegistrationRepository; - return this; - } - - /** - * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look - * the value up as a Bean. - * @param authorizedClientRepository the repository to use - * @return the {@link OAuth2ClientSpec} to customize - */ - public OAuth2ClientSpec authorizedClientRepository( - ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { - this.authorizedClientRepository = authorizedClientRepository; - return this; - } - - /** - * Sets the repository to use for storing {@link OAuth2AuthorizationRequest}'s. - * @param authorizationRequestRepository the repository to use for storing - * {@link OAuth2AuthorizationRequest}'s - * @return the {@link OAuth2ClientSpec} to customize - * @since 5.2 - */ - public OAuth2ClientSpec authorizationRequestRepository( - ServerAuthorizationRequestRepository authorizationRequestRepository) { - this.authorizationRequestRepository = authorizationRequestRepository; - return this; - } - - private ServerAuthorizationRequestRepository getAuthorizationRequestRepository() { - if (this.authorizationRequestRepository == null) { - this.authorizationRequestRepository = new WebSessionOAuth2ServerAuthorizationRequestRepository(); - } - return this.authorizationRequestRepository; - } - - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - */ - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - - protected void configure(ServerHttpSecurity http) { - ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); - ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); - ServerAuthenticationConverter authenticationConverter = getAuthenticationConverter(); - ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); - OAuth2AuthorizationCodeGrantWebFilter codeGrantWebFilter = new OAuth2AuthorizationCodeGrantWebFilter( - authenticationManager, authenticationConverter, authorizedClientRepository); - codeGrantWebFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); - if (http.requestCache != null) { - codeGrantWebFilter.setRequestCache(http.requestCache.requestCache); - } - - OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( - clientRegistrationRepository); - oauthRedirectFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); - if (http.requestCache != null) { - oauthRedirectFilter.setRequestCache(http.requestCache.requestCache); - } - - http.addFilterAt(codeGrantWebFilter, SecurityWebFiltersOrder.OAUTH2_AUTHORIZATION_CODE); - http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); - } - - private ReactiveClientRegistrationRepository getClientRegistrationRepository() { - if (this.clientRegistrationRepository != null) { - return this.clientRegistrationRepository; - } - return getBeanOrNull(ReactiveClientRegistrationRepository.class); - } - - private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() { - if (this.authorizedClientRepository != null) { - return this.authorizedClientRepository; - } - ServerOAuth2AuthorizedClientRepository result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class); - if (result == null) { - ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService(); - if (authorizedClientService != null) { - result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService); - } - } - return result; - } - - private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() { - ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class); - if (service == null) { - service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository()); - } - return service; - } - - } - /** * Configures OAuth 2.0 Resource Server support. * @@ -1654,442 +964,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures OAuth2 Resource Server Support - */ - public class OAuth2ResourceServerSpec { - - private ServerAuthenticationEntryPoint entryPoint = new BearerTokenServerAuthenticationEntryPoint(); - - private ServerAccessDeniedHandler accessDeniedHandler = new BearerTokenServerAccessDeniedHandler(); - - private ServerAuthenticationConverter bearerTokenConverter = new ServerBearerTokenAuthenticationConverter(); - - private AuthenticationConverterServerWebExchangeMatcher authenticationConverterServerWebExchangeMatcher; - - private JwtSpec jwt; - - private OpaqueTokenSpec opaqueToken; - - private ReactiveAuthenticationManagerResolver authenticationManagerResolver; - - /** - * Configures the {@link ServerAccessDeniedHandler} to use for requests - * authenticating with - * Bearer Tokens. requests. - * @param accessDeniedHandler the {@link ServerAccessDeniedHandler} to use - * @return the {@link OAuth2ResourceServerSpec} for additional configuration - * @since 5.2 - */ - public OAuth2ResourceServerSpec accessDeniedHandler(ServerAccessDeniedHandler accessDeniedHandler) { - Assert.notNull(accessDeniedHandler, "accessDeniedHandler cannot be null"); - this.accessDeniedHandler = accessDeniedHandler; - return this; - } - - /** - * Configures the {@link ServerAuthenticationEntryPoint} to use for requests - * authenticating with - * Bearer Tokens. - * @param entryPoint the {@link ServerAuthenticationEntryPoint} to use - * @return the {@link OAuth2ResourceServerSpec} for additional configuration - * @since 5.2 - */ - public OAuth2ResourceServerSpec authenticationEntryPoint(ServerAuthenticationEntryPoint entryPoint) { - Assert.notNull(entryPoint, "entryPoint cannot be null"); - this.entryPoint = entryPoint; - return this; - } - - /** - * Configures the {@link ServerAuthenticationConverter} to use for requests - * authenticating with - * Bearer Tokens. - * @param bearerTokenConverter The {@link ServerAuthenticationConverter} to use - * @return The {@link OAuth2ResourceServerSpec} for additional configuration - * @since 5.2 - */ - public OAuth2ResourceServerSpec bearerTokenConverter(ServerAuthenticationConverter bearerTokenConverter) { - Assert.notNull(bearerTokenConverter, "bearerTokenConverter cannot be null"); - this.bearerTokenConverter = bearerTokenConverter; - return this; - } - - /** - * Configures the {@link ReactiveAuthenticationManagerResolver} - * @param authenticationManagerResolver the - * {@link ReactiveAuthenticationManagerResolver} - * @return the {@link OAuth2ResourceServerSpec} for additional configuration - * @since 5.3 - */ - public OAuth2ResourceServerSpec authenticationManagerResolver( - ReactiveAuthenticationManagerResolver authenticationManagerResolver) { - Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null"); - this.authenticationManagerResolver = authenticationManagerResolver; - return this; - } - - /** - * Enables JWT Resource Server support. - * @return the {@link JwtSpec} for additional configuration - */ - public JwtSpec jwt() { - if (this.jwt == null) { - this.jwt = new JwtSpec(); - } - return this.jwt; - } - - /** - * Enables JWT Resource Server support. - * @param jwtCustomizer the {@link Customizer} to provide more options for the - * {@link JwtSpec} - * @return the {@link OAuth2ResourceServerSpec} to customize - */ - public OAuth2ResourceServerSpec jwt(Customizer jwtCustomizer) { - if (this.jwt == null) { - this.jwt = new JwtSpec(); - } - jwtCustomizer.customize(this.jwt); - return this; - } - - /** - * Enables Opaque Token Resource Server support. - * @return the {@link OpaqueTokenSpec} for additional configuration - */ - public OpaqueTokenSpec opaqueToken() { - if (this.opaqueToken == null) { - this.opaqueToken = new OpaqueTokenSpec(); - } - return this.opaqueToken; - } - - /** - * Enables Opaque Token Resource Server support. - * @param opaqueTokenCustomizer the {@link Customizer} to provide more options for - * the {@link OpaqueTokenSpec} - * @return the {@link OAuth2ResourceServerSpec} to customize - */ - public OAuth2ResourceServerSpec opaqueToken(Customizer opaqueTokenCustomizer) { - if (this.opaqueToken == null) { - this.opaqueToken = new OpaqueTokenSpec(); - } - opaqueTokenCustomizer.customize(this.opaqueToken); - return this; - } - - protected void configure(ServerHttpSecurity http) { - this.authenticationConverterServerWebExchangeMatcher = new AuthenticationConverterServerWebExchangeMatcher( - this.bearerTokenConverter); - - registerDefaultAccessDeniedHandler(http); - registerDefaultAuthenticationEntryPoint(http); - registerDefaultCsrfOverride(http); - - validateConfiguration(); - - if (this.authenticationManagerResolver != null) { - AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(this.authenticationManagerResolver); - oauth2.setServerAuthenticationConverter(this.bearerTokenConverter); - oauth2.setAuthenticationFailureHandler( - new ServerAuthenticationEntryPointFailureHandler(this.entryPoint)); - http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); - } - else if (this.jwt != null) { - this.jwt.configure(http); - } - else if (this.opaqueToken != null) { - this.opaqueToken.configure(http); - } - } - - private void validateConfiguration() { - if (this.authenticationManagerResolver == null) { - if (this.jwt == null && this.opaqueToken == null) { - throw new IllegalStateException( - "Jwt and Opaque Token are the only supported formats for bearer tokens " - + "in Spring Security and neither was found. Make sure to configure JWT " - + "via http.oauth2ResourceServer().jwt() or Opaque Tokens via " - + "http.oauth2ResourceServer().opaqueToken()."); - } - - if (this.jwt != null && this.opaqueToken != null) { - throw new IllegalStateException( - "Spring Security only supports JWTs or Opaque Tokens, not both at the " + "same time."); - } - } - else { - if (this.jwt != null || this.opaqueToken != null) { - throw new IllegalStateException( - "If an authenticationManagerResolver() is configured, then it takes " - + "precedence over any jwt() or opaqueToken() configuration."); - } - } - } - - private void registerDefaultAccessDeniedHandler(ServerHttpSecurity http) { - if (http.exceptionHandling != null) { - http.defaultAccessDeniedHandlers - .add(new ServerWebExchangeDelegatingServerAccessDeniedHandler.DelegateEntry( - this.authenticationConverterServerWebExchangeMatcher, - OAuth2ResourceServerSpec.this.accessDeniedHandler)); - } - } - - private void registerDefaultAuthenticationEntryPoint(ServerHttpSecurity http) { - if (http.exceptionHandling != null) { - http.defaultEntryPoints.add(new DelegateEntry(this.authenticationConverterServerWebExchangeMatcher, - OAuth2ResourceServerSpec.this.entryPoint)); - } - } - - private void registerDefaultCsrfOverride(ServerHttpSecurity http) { - if (http.csrf != null && !http.csrf.specifiedRequireCsrfProtectionMatcher) { - // @formatter:off - http - .csrf() - .requireCsrfProtectionMatcher( - new AndServerWebExchangeMatcher( - CsrfWebFilter.DEFAULT_CSRF_MATCHER, - new NegatedServerWebExchangeMatcher( - this.authenticationConverterServerWebExchangeMatcher))); - // @formatter:on - } - } - - private class BearerTokenAuthenticationWebFilter extends AuthenticationWebFilter { - - private ServerAuthenticationFailureHandler authenticationFailureHandler; - - BearerTokenAuthenticationWebFilter(ReactiveAuthenticationManager authenticationManager) { - super(authenticationManager); - } - - @Override - public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { - WebFilterExchange webFilterExchange = new WebFilterExchange(exchange, chain); - return super.filter(exchange, chain).onErrorResume(AuthenticationException.class, - e -> this.authenticationFailureHandler.onAuthenticationFailure(webFilterExchange, e)); - } - - @Override - public void setAuthenticationFailureHandler( - ServerAuthenticationFailureHandler authenticationFailureHandler) { - super.setAuthenticationFailureHandler(authenticationFailureHandler); - this.authenticationFailureHandler = authenticationFailureHandler; - } - - } - - /** - * Configures JWT Resource Server Support - */ - public class JwtSpec { - - private ReactiveAuthenticationManager authenticationManager; - - private ReactiveJwtDecoder jwtDecoder; - - private Converter> jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverterAdapter( - new JwtAuthenticationConverter()); - - /** - * Configures the {@link ReactiveAuthenticationManager} to use - * @param authenticationManager the authentication manager to use - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { - Assert.notNull(authenticationManager, "authenticationManager cannot be null"); - this.authenticationManager = authenticationManager; - return this; - } - - /** - * Configures the {@link Converter} to use for converting a {@link Jwt} into - * an {@link AbstractAuthenticationToken}. - * @param jwtAuthenticationConverter the converter to use - * @return the {@code JwtSpec} for additional configuration - * @since 5.1.1 - */ - public JwtSpec jwtAuthenticationConverter( - Converter> jwtAuthenticationConverter) { - Assert.notNull(jwtAuthenticationConverter, "jwtAuthenticationConverter cannot be null"); - this.jwtAuthenticationConverter = jwtAuthenticationConverter; - return this; - } - - /** - * Configures the {@link ReactiveJwtDecoder} to use - * @param jwtDecoder the decoder to use - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec jwtDecoder(ReactiveJwtDecoder jwtDecoder) { - this.jwtDecoder = jwtDecoder; - return this; - } - - /** - * Configures a {@link ReactiveJwtDecoder} that leverages the provided - * {@link RSAPublicKey} - * @param publicKey the public key to use. - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec publicKey(RSAPublicKey publicKey) { - this.jwtDecoder = new NimbusReactiveJwtDecoder(publicKey); - return this; - } - - /** - * Configures a {@link ReactiveJwtDecoder} using - * JSON Web Key - * (JWK) URL - * @param jwkSetUri the URL to use. - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec jwkSetUri(String jwkSetUri) { - this.jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri); - return this; - } - - public OAuth2ResourceServerSpec and() { - return OAuth2ResourceServerSpec.this; - } - - protected void configure(ServerHttpSecurity http) { - ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); - AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager); - oauth2.setServerAuthenticationConverter(OAuth2ResourceServerSpec.this.bearerTokenConverter); - oauth2.setAuthenticationFailureHandler( - new ServerAuthenticationEntryPointFailureHandler(OAuth2ResourceServerSpec.this.entryPoint)); - // @formatter:off - http - .addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); - // @formatter:on - } - - protected ReactiveJwtDecoder getJwtDecoder() { - if (this.jwtDecoder == null) { - return getBean(ReactiveJwtDecoder.class); - } - return this.jwtDecoder; - } - - protected Converter> getJwtAuthenticationConverter() { - - return this.jwtAuthenticationConverter; - } - - private ReactiveAuthenticationManager getAuthenticationManager() { - if (this.authenticationManager != null) { - return this.authenticationManager; - } - - ReactiveJwtDecoder jwtDecoder = getJwtDecoder(); - Converter> jwtAuthenticationConverter = getJwtAuthenticationConverter(); - JwtReactiveAuthenticationManager authenticationManager = new JwtReactiveAuthenticationManager( - jwtDecoder); - authenticationManager.setJwtAuthenticationConverter(jwtAuthenticationConverter); - - return authenticationManager; - } - - } - - /** - * Configures Opaque Token Resource Server support - * - * @author Josh Cummings - * @since 5.2 - */ - public final class OpaqueTokenSpec { - - private String introspectionUri; - - private String clientId; - - private String clientSecret; - - private Supplier introspector; - - private OpaqueTokenSpec() { - } - - /** - * Configures the URI of the Introspection endpoint - * @param introspectionUri The URI of the Introspection endpoint - * @return the {@code OpaqueTokenSpec} for additional configuration - */ - public OpaqueTokenSpec introspectionUri(String introspectionUri) { - Assert.hasText(introspectionUri, "introspectionUri cannot be empty"); - this.introspectionUri = introspectionUri; - this.introspector = () -> new NimbusReactiveOpaqueTokenIntrospector(this.introspectionUri, - this.clientId, this.clientSecret); - return this; - } - - /** - * Configures the credentials for Introspection endpoint - * @param clientId The clientId part of the credentials - * @param clientSecret The clientSecret part of the credentials - * @return the {@code OpaqueTokenSpec} for additional configuration - */ - public OpaqueTokenSpec introspectionClientCredentials(String clientId, String clientSecret) { - Assert.hasText(clientId, "clientId cannot be empty"); - Assert.notNull(clientSecret, "clientSecret cannot be null"); - this.clientId = clientId; - this.clientSecret = clientSecret; - this.introspector = () -> new NimbusReactiveOpaqueTokenIntrospector(this.introspectionUri, - this.clientId, this.clientSecret); - return this; - } - - public OpaqueTokenSpec introspector(ReactiveOpaqueTokenIntrospector introspector) { - Assert.notNull(introspector, "introspector cannot be null"); - this.introspector = () -> introspector; - return this; - } - - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - */ - public OAuth2ResourceServerSpec and() { - return OAuth2ResourceServerSpec.this; - } - - protected ReactiveAuthenticationManager getAuthenticationManager() { - return new OpaqueTokenReactiveAuthenticationManager(getIntrospector()); - } - - protected ReactiveOpaqueTokenIntrospector getIntrospector() { - if (this.introspector != null) { - return this.introspector.get(); - } - return getBean(ReactiveOpaqueTokenIntrospector.class); - } - - protected void configure(ServerHttpSecurity http) { - ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); - AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager); - oauth2.setServerAuthenticationConverter(OAuth2ResourceServerSpec.this.bearerTokenConverter); - oauth2.setAuthenticationFailureHandler( - new ServerAuthenticationEntryPointFailureHandler(OAuth2ResourceServerSpec.this.entryPoint)); - http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); - } - - } - - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - - } - /** * Configures HTTP Response Headers. The default headers are: * @@ -2599,7 +1473,30 @@ public class ServerHttpSecurity { return new OrderedWebFilter(result, SecurityWebFiltersOrder.REACTOR_CONTEXT.getOrder()); } - protected ServerHttpSecurity() { + private T getBean(Class beanClass) { + if (this.context == null) { + return null; + } + return this.context.getBean(beanClass); + } + + private T getBeanOrNull(Class beanClass) { + return getBeanOrNull(ResolvableType.forClass(beanClass)); + } + + private T getBeanOrNull(ResolvableType type) { + if (this.context == null) { + return null; + } + String[] names = this.context.getBeanNamesForType(type); + if (names.length == 1) { + return (T) this.context.getBean(names[0]); + } + return null; + } + + protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.context = applicationContext; } /** @@ -3931,32 +2828,6 @@ public class ServerHttpSecurity { } - private T getBean(Class beanClass) { - if (this.context == null) { - return null; - } - return this.context.getBean(beanClass); - } - - private T getBeanOrNull(Class beanClass) { - return getBeanOrNull(ResolvableType.forClass(beanClass)); - } - - private T getBeanOrNull(ResolvableType type) { - if (this.context == null) { - return null; - } - String[] names = this.context.getBeanNamesForType(type); - if (names.length == 1) { - return (T) this.context.getBean(names[0]); - } - return null; - } - - protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.context = applicationContext; - } - private static class OrderedWebFilter implements WebFilter, Ordered { private final WebFilter webFilter; @@ -3997,6 +2868,1135 @@ public class ServerHttpSecurity { } + /** + * Configures CORS support within Spring Security. This ensures that the + * {@link CorsWebFilter} is place in the correct order. + */ + public final class CorsSpec { + + private CorsWebFilter corsFilter; + + private CorsSpec() { + } + + /** + * Configures the {@link CorsConfigurationSource} to be used + * @param source the source to use + * @return the {@link CorsSpec} for additional configuration + */ + public CorsSpec configurationSource(CorsConfigurationSource source) { + this.corsFilter = new CorsWebFilter(source); + return this; + } + + /** + * Disables CORS support within Spring Security. + * @return the {@link ServerHttpSecurity} to continue configuring + */ + public ServerHttpSecurity disable() { + ServerHttpSecurity.this.cors = null; + return ServerHttpSecurity.this; + } + + /** + * Allows method chaining to continue configuring the {@link ServerHttpSecurity} + * @return the {@link ServerHttpSecurity} to continue configuring + */ + public ServerHttpSecurity and() { + return ServerHttpSecurity.this; + } + + protected void configure(ServerHttpSecurity http) { + CorsWebFilter corsFilter = getCorsFilter(); + if (corsFilter != null) { + http.addFilterAt(this.corsFilter, SecurityWebFiltersOrder.CORS); + } + } + + private CorsWebFilter getCorsFilter() { + if (this.corsFilter != null) { + return this.corsFilter; + } + + CorsConfigurationSource source = getBeanOrNull(CorsConfigurationSource.class); + if (source == null) { + return null; + } + CorsProcessor processor = getBeanOrNull(CorsProcessor.class); + if (processor == null) { + processor = new DefaultCorsProcessor(); + } + this.corsFilter = new CorsWebFilter(source, processor); + return this.corsFilter; + } + + } + + /** + * Configures X509 authentication + * + * @author Alexey Nesterov + * @since 5.2 + * @see #x509() + */ + public final class X509Spec { + + private X509PrincipalExtractor principalExtractor; + + private ReactiveAuthenticationManager authenticationManager; + + private X509Spec() { + } + + public X509Spec principalExtractor(X509PrincipalExtractor principalExtractor) { + this.principalExtractor = principalExtractor; + return this; + } + + public X509Spec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + return this; + } + + public ServerHttpSecurity and() { + return ServerHttpSecurity.this; + } + + protected void configure(ServerHttpSecurity http) { + ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); + X509PrincipalExtractor principalExtractor = getPrincipalExtractor(); + + AuthenticationWebFilter filter = new AuthenticationWebFilter(authenticationManager); + filter.setServerAuthenticationConverter(new ServerX509AuthenticationConverter(principalExtractor)); + http.addFilterAt(filter, SecurityWebFiltersOrder.AUTHENTICATION); + } + + private X509PrincipalExtractor getPrincipalExtractor() { + if (this.principalExtractor != null) { + return this.principalExtractor; + } + + return new SubjectDnX509PrincipalExtractor(); + } + + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager != null) { + return this.authenticationManager; + } + + ReactiveUserDetailsService userDetailsService = getBean(ReactiveUserDetailsService.class); + ReactivePreAuthenticatedAuthenticationManager authenticationManager = new ReactivePreAuthenticatedAuthenticationManager( + userDetailsService); + + return authenticationManager; + } + + } + + public final class OAuth2LoginSpec { + + private ReactiveClientRegistrationRepository clientRegistrationRepository; + + private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; + + private ServerAuthorizationRequestRepository authorizationRequestRepository; + + private ReactiveAuthenticationManager authenticationManager; + + private ServerSecurityContextRepository securityContextRepository; + + private ServerAuthenticationConverter authenticationConverter; + + private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver; + + private ServerWebExchangeMatcher authenticationMatcher; + + private ServerAuthenticationSuccessHandler authenticationSuccessHandler; + + private ServerAuthenticationFailureHandler authenticationFailureHandler; + + private OAuth2LoginSpec() { + } + + /** + * Configures the {@link ReactiveAuthenticationManager} to use. The default is + * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} + * @param authenticationManager the manager to use + * @return the {@link OAuth2LoginSpec} to customize + */ + public OAuth2LoginSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + return this; + } + + /** + * The {@link ServerSecurityContextRepository} used to save the + * {@code Authentication}. Defaults to + * {@link WebSessionServerSecurityContextRepository}. + * @param securityContextRepository the repository to use + * @return the {@link OAuth2LoginSpec} to continue configuring + * @since 5.2 + */ + public OAuth2LoginSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) { + this.securityContextRepository = securityContextRepository; + return this; + } + + /** + * The {@link ServerAuthenticationSuccessHandler} used after authentication + * success. Defaults to {@link RedirectServerAuthenticationSuccessHandler} + * redirecting to "/". + * @param authenticationSuccessHandler the success handler to use + * @return the {@link OAuth2LoginSpec} to customize + * @since 5.2 + */ + public OAuth2LoginSpec authenticationSuccessHandler( + ServerAuthenticationSuccessHandler authenticationSuccessHandler) { + Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null"); + this.authenticationSuccessHandler = authenticationSuccessHandler; + return this; + } + + /** + * The {@link ServerAuthenticationFailureHandler} used after authentication + * failure. Defaults to {@link RedirectServerAuthenticationFailureHandler} + * redirecting to "/login?error". + * @param authenticationFailureHandler the failure handler to use + * @return the {@link OAuth2LoginSpec} to customize + * @since 5.2 + */ + public OAuth2LoginSpec authenticationFailureHandler( + ServerAuthenticationFailureHandler authenticationFailureHandler) { + Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null"); + this.authenticationFailureHandler = authenticationFailureHandler; + return this; + } + + /** + * Gets the {@link ReactiveAuthenticationManager} to use. First tries an + * explicitly configured manager, and defaults to + * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} + * @return the {@link ReactiveAuthenticationManager} to use + */ + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager == null) { + this.authenticationManager = createDefault(); + } + return this.authenticationManager; + } + + private ReactiveAuthenticationManager createDefault() { + ReactiveOAuth2AccessTokenResponseClient client = getAccessTokenResponseClient(); + OAuth2LoginReactiveAuthenticationManager oauth2Manager = new OAuth2LoginReactiveAuthenticationManager( + client, getOauth2UserService()); + GrantedAuthoritiesMapper authoritiesMapper = getBeanOrNull(GrantedAuthoritiesMapper.class); + if (authoritiesMapper != null) { + oauth2Manager.setAuthoritiesMapper(authoritiesMapper); + } + boolean oidcAuthenticationProviderEnabled = ClassUtils + .isPresent("org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader()); + if (oidcAuthenticationProviderEnabled) { + OidcAuthorizationCodeReactiveAuthenticationManager oidc = new OidcAuthorizationCodeReactiveAuthenticationManager( + client, getOidcUserService()); + ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveJwtDecoderFactory.class, + ClientRegistration.class); + ReactiveJwtDecoderFactory jwtDecoderFactory = getBeanOrNull(type); + if (jwtDecoderFactory != null) { + oidc.setJwtDecoderFactory(jwtDecoderFactory); + } + if (authoritiesMapper != null) { + oidc.setAuthoritiesMapper(authoritiesMapper); + } + return new DelegatingReactiveAuthenticationManager(oidc, oauth2Manager); + } + return oauth2Manager; + } + + /** + * Sets the converter to use + * @param authenticationConverter the converter to use + * @return the {@link OAuth2LoginSpec} to customize + */ + public OAuth2LoginSpec authenticationConverter(ServerAuthenticationConverter authenticationConverter) { + this.authenticationConverter = authenticationConverter; + return this; + } + + private ServerAuthenticationConverter getAuthenticationConverter( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + if (this.authenticationConverter == null) { + ServerOAuth2AuthorizationCodeAuthenticationTokenConverter delegate = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter( + clientRegistrationRepository); + delegate.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); + ServerAuthenticationConverter authenticationConverter = exchange -> delegate.convert(exchange) + .onErrorMap(OAuth2AuthorizationException.class, + e -> new OAuth2AuthenticationException(e.getError(), e.getError().toString())); + this.authenticationConverter = authenticationConverter; + return authenticationConverter; + } + return this.authenticationConverter; + } + + public OAuth2LoginSpec clientRegistrationRepository( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + this.clientRegistrationRepository = clientRegistrationRepository; + return this; + } + + public OAuth2LoginSpec authorizedClientService(ReactiveOAuth2AuthorizedClientService authorizedClientService) { + this.authorizedClientRepository = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository( + authorizedClientService); + return this; + } + + public OAuth2LoginSpec authorizedClientRepository( + ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { + this.authorizedClientRepository = authorizedClientRepository; + return this; + } + + /** + * Sets the repository to use for storing {@link OAuth2AuthorizationRequest}'s. + * @param authorizationRequestRepository the repository to use for storing + * {@link OAuth2AuthorizationRequest}'s + * @return the {@link OAuth2LoginSpec} for further configuration + * @since 5.2 + */ + public OAuth2LoginSpec authorizationRequestRepository( + ServerAuthorizationRequestRepository authorizationRequestRepository) { + this.authorizationRequestRepository = authorizationRequestRepository; + return this; + } + + /** + * Sets the resolver used for resolving {@link OAuth2AuthorizationRequest}'s. + * @param authorizationRequestResolver the resolver used for resolving + * {@link OAuth2AuthorizationRequest}'s + * @return the {@link OAuth2LoginSpec} for further configuration + * @since 5.2 + */ + public OAuth2LoginSpec authorizationRequestResolver( + ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) { + this.authorizationRequestResolver = authorizationRequestResolver; + return this; + } + + /** + * Sets the {@link ServerWebExchangeMatcher matcher} used for determining if the + * request is an authentication request. + * @param authenticationMatcher the {@link ServerWebExchangeMatcher matcher} used + * for determining if the request is an authentication request + * @return the {@link OAuth2LoginSpec} for further configuration + * @since 5.2 + */ + public OAuth2LoginSpec authenticationMatcher(ServerWebExchangeMatcher authenticationMatcher) { + this.authenticationMatcher = authenticationMatcher; + return this; + } + + private ServerWebExchangeMatcher getAuthenticationMatcher() { + if (this.authenticationMatcher == null) { + this.authenticationMatcher = createAttemptAuthenticationRequestMatcher(); + } + return this.authenticationMatcher; + } + + /** + * Allows method chaining to continue configuring the {@link ServerHttpSecurity} + * @return the {@link ServerHttpSecurity} to continue configuring + */ + public ServerHttpSecurity and() { + return ServerHttpSecurity.this; + } + + protected void configure(ServerHttpSecurity http) { + ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); + ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); + OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = getRedirectWebFilter(); + ServerAuthorizationRequestRepository authorizationRequestRepository = getAuthorizationRequestRepository(); + oauthRedirectFilter.setAuthorizationRequestRepository(authorizationRequestRepository); + oauthRedirectFilter.setRequestCache(http.requestCache.requestCache); + + ReactiveAuthenticationManager manager = getAuthenticationManager(); + + AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager, + authorizedClientRepository); + authenticationFilter.setRequiresAuthenticationMatcher(getAuthenticationMatcher()); + authenticationFilter + .setServerAuthenticationConverter(getAuthenticationConverter(clientRegistrationRepository)); + + authenticationFilter.setAuthenticationSuccessHandler(getAuthenticationSuccessHandler(http)); + authenticationFilter.setAuthenticationFailureHandler(getAuthenticationFailureHandler()); + authenticationFilter.setSecurityContextRepository(this.securityContextRepository); + + setDefaultEntryPoints(http); + + http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); + http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION); + } + + private void setDefaultEntryPoints(ServerHttpSecurity http) { + String defaultLoginPage = "/login"; + Map 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(); + handler.setRequestCache(http.requestCache.requestCache); + this.authenticationSuccessHandler = handler; + } + return this.authenticationSuccessHandler; + } + + private ServerAuthenticationFailureHandler getAuthenticationFailureHandler() { + if (this.authenticationFailureHandler == null) { + this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler("/login?error"); + } + return this.authenticationFailureHandler; + } + + private ServerWebExchangeMatcher createAttemptAuthenticationRequestMatcher() { + return new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}"); + } + + private ReactiveOAuth2UserService getOidcUserService() { + ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, + OidcUserRequest.class, OidcUser.class); + ReactiveOAuth2UserService bean = getBeanOrNull(type); + if (bean == null) { + return new OidcReactiveOAuth2UserService(); + } + + return bean; + } + + private ReactiveOAuth2UserService getOauth2UserService() { + ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2UserService.class, + OAuth2UserRequest.class, OAuth2User.class); + ReactiveOAuth2UserService bean = getBeanOrNull(type); + if (bean == null) { + return new DefaultReactiveOAuth2UserService(); + } + + return bean; + } + + private Map getLinks() { + Iterable registrations = getBeanOrNull( + ResolvableType.forClassWithGenerics(Iterable.class, ClientRegistration.class)); + if (registrations == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + registrations.iterator().forEachRemaining( + r -> result.put("/oauth2/authorization/" + r.getRegistrationId(), r.getClientName())); + return result; + } + + private ReactiveOAuth2AccessTokenResponseClient getAccessTokenResponseClient() { + ResolvableType type = ResolvableType.forClassWithGenerics(ReactiveOAuth2AccessTokenResponseClient.class, + OAuth2AuthorizationCodeGrantRequest.class); + ReactiveOAuth2AccessTokenResponseClient bean = getBeanOrNull(type); + if (bean == null) { + return new WebClientReactiveAuthorizationCodeTokenResponseClient(); + } + return bean; + } + + private ReactiveClientRegistrationRepository getClientRegistrationRepository() { + if (this.clientRegistrationRepository == null) { + this.clientRegistrationRepository = getBeanOrNull(ReactiveClientRegistrationRepository.class); + } + return this.clientRegistrationRepository; + } + + private OAuth2AuthorizationRequestRedirectWebFilter getRedirectWebFilter() { + OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter; + if (this.authorizationRequestResolver == null) { + oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( + getClientRegistrationRepository()); + } + else { + oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( + this.authorizationRequestResolver); + } + return oauthRedirectFilter; + } + + private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() { + ServerOAuth2AuthorizedClientRepository result = this.authorizedClientRepository; + if (result == null) { + result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class); + } + if (result == null) { + ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService(); + if (authorizedClientService != null) { + result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService); + } + } + return result; + } + + private ServerAuthorizationRequestRepository getAuthorizationRequestRepository() { + if (this.authorizationRequestRepository == null) { + this.authorizationRequestRepository = new WebSessionOAuth2ServerAuthorizationRequestRepository(); + } + return this.authorizationRequestRepository; + } + + private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() { + ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class); + if (service == null) { + service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository()); + } + return service; + } + + } + + public final class OAuth2ClientSpec { + + private ReactiveClientRegistrationRepository clientRegistrationRepository; + + private ServerAuthenticationConverter authenticationConverter; + + private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; + + private ReactiveAuthenticationManager authenticationManager; + + private ServerAuthorizationRequestRepository authorizationRequestRepository; + + private OAuth2ClientSpec() { + } + + /** + * Sets the converter to use + * @param authenticationConverter the converter to use + * @return the {@link OAuth2ClientSpec} to customize + */ + public OAuth2ClientSpec authenticationConverter(ServerAuthenticationConverter authenticationConverter) { + this.authenticationConverter = authenticationConverter; + return this; + } + + private ServerAuthenticationConverter getAuthenticationConverter() { + if (this.authenticationConverter == null) { + ServerOAuth2AuthorizationCodeAuthenticationTokenConverter authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter( + getClientRegistrationRepository()); + authenticationConverter.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); + this.authenticationConverter = authenticationConverter; + } + return this.authenticationConverter; + } + + /** + * Configures the {@link ReactiveAuthenticationManager} to use. The default is + * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} + * @param authenticationManager the manager to use + * @return the {@link OAuth2ClientSpec} to customize + */ + public OAuth2ClientSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + return this; + } + + /** + * Gets the {@link ReactiveAuthenticationManager} to use. First tries an + * explicitly configured manager, and defaults to + * {@link OAuth2AuthorizationCodeReactiveAuthenticationManager} + * @return the {@link ReactiveAuthenticationManager} to use + */ + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager == null) { + this.authenticationManager = new OAuth2AuthorizationCodeReactiveAuthenticationManager( + new WebClientReactiveAuthorizationCodeTokenResponseClient()); + } + return this.authenticationManager; + } + + /** + * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look + * the value up as a Bean. + * @param clientRegistrationRepository the repository to use + * @return the {@link OAuth2ClientSpec} to customize + */ + public OAuth2ClientSpec clientRegistrationRepository( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + this.clientRegistrationRepository = clientRegistrationRepository; + return this; + } + + /** + * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look + * the value up as a Bean. + * @param authorizedClientRepository the repository to use + * @return the {@link OAuth2ClientSpec} to customize + */ + public OAuth2ClientSpec authorizedClientRepository( + ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { + this.authorizedClientRepository = authorizedClientRepository; + return this; + } + + /** + * Sets the repository to use for storing {@link OAuth2AuthorizationRequest}'s. + * @param authorizationRequestRepository the repository to use for storing + * {@link OAuth2AuthorizationRequest}'s + * @return the {@link OAuth2ClientSpec} to customize + * @since 5.2 + */ + public OAuth2ClientSpec authorizationRequestRepository( + ServerAuthorizationRequestRepository authorizationRequestRepository) { + this.authorizationRequestRepository = authorizationRequestRepository; + return this; + } + + private ServerAuthorizationRequestRepository getAuthorizationRequestRepository() { + if (this.authorizationRequestRepository == null) { + this.authorizationRequestRepository = new WebSessionOAuth2ServerAuthorizationRequestRepository(); + } + return this.authorizationRequestRepository; + } + + /** + * Allows method chaining to continue configuring the {@link ServerHttpSecurity} + * @return the {@link ServerHttpSecurity} to continue configuring + */ + public ServerHttpSecurity and() { + return ServerHttpSecurity.this; + } + + protected void configure(ServerHttpSecurity http) { + ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); + ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); + ServerAuthenticationConverter authenticationConverter = getAuthenticationConverter(); + ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); + OAuth2AuthorizationCodeGrantWebFilter codeGrantWebFilter = new OAuth2AuthorizationCodeGrantWebFilter( + authenticationManager, authenticationConverter, authorizedClientRepository); + codeGrantWebFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); + if (http.requestCache != null) { + codeGrantWebFilter.setRequestCache(http.requestCache.requestCache); + } + + OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( + clientRegistrationRepository); + oauthRedirectFilter.setAuthorizationRequestRepository(getAuthorizationRequestRepository()); + if (http.requestCache != null) { + oauthRedirectFilter.setRequestCache(http.requestCache.requestCache); + } + + http.addFilterAt(codeGrantWebFilter, SecurityWebFiltersOrder.OAUTH2_AUTHORIZATION_CODE); + http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); + } + + private ReactiveClientRegistrationRepository getClientRegistrationRepository() { + if (this.clientRegistrationRepository != null) { + return this.clientRegistrationRepository; + } + return getBeanOrNull(ReactiveClientRegistrationRepository.class); + } + + private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() { + if (this.authorizedClientRepository != null) { + return this.authorizedClientRepository; + } + ServerOAuth2AuthorizedClientRepository result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class); + if (result == null) { + ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService(); + if (authorizedClientService != null) { + result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService); + } + } + return result; + } + + private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() { + ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class); + if (service == null) { + service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository()); + } + return service; + } + + } + + /** + * Configures OAuth2 Resource Server Support + */ + public class OAuth2ResourceServerSpec { + + private ServerAuthenticationEntryPoint entryPoint = new BearerTokenServerAuthenticationEntryPoint(); + + private ServerAccessDeniedHandler accessDeniedHandler = new BearerTokenServerAccessDeniedHandler(); + + private ServerAuthenticationConverter bearerTokenConverter = new ServerBearerTokenAuthenticationConverter(); + + private AuthenticationConverterServerWebExchangeMatcher authenticationConverterServerWebExchangeMatcher; + + private JwtSpec jwt; + + private OpaqueTokenSpec opaqueToken; + + private ReactiveAuthenticationManagerResolver authenticationManagerResolver; + + /** + * Configures the {@link ServerAccessDeniedHandler} to use for requests + * authenticating with + * Bearer Tokens. requests. + * @param accessDeniedHandler the {@link ServerAccessDeniedHandler} to use + * @return the {@link OAuth2ResourceServerSpec} for additional configuration + * @since 5.2 + */ + public OAuth2ResourceServerSpec accessDeniedHandler(ServerAccessDeniedHandler accessDeniedHandler) { + Assert.notNull(accessDeniedHandler, "accessDeniedHandler cannot be null"); + this.accessDeniedHandler = accessDeniedHandler; + return this; + } + + /** + * Configures the {@link ServerAuthenticationEntryPoint} to use for requests + * authenticating with + * Bearer Tokens. + * @param entryPoint the {@link ServerAuthenticationEntryPoint} to use + * @return the {@link OAuth2ResourceServerSpec} for additional configuration + * @since 5.2 + */ + public OAuth2ResourceServerSpec authenticationEntryPoint(ServerAuthenticationEntryPoint entryPoint) { + Assert.notNull(entryPoint, "entryPoint cannot be null"); + this.entryPoint = entryPoint; + return this; + } + + /** + * Configures the {@link ServerAuthenticationConverter} to use for requests + * authenticating with + * Bearer Tokens. + * @param bearerTokenConverter The {@link ServerAuthenticationConverter} to use + * @return The {@link OAuth2ResourceServerSpec} for additional configuration + * @since 5.2 + */ + public OAuth2ResourceServerSpec bearerTokenConverter(ServerAuthenticationConverter bearerTokenConverter) { + Assert.notNull(bearerTokenConverter, "bearerTokenConverter cannot be null"); + this.bearerTokenConverter = bearerTokenConverter; + return this; + } + + /** + * Configures the {@link ReactiveAuthenticationManagerResolver} + * @param authenticationManagerResolver the + * {@link ReactiveAuthenticationManagerResolver} + * @return the {@link OAuth2ResourceServerSpec} for additional configuration + * @since 5.3 + */ + public OAuth2ResourceServerSpec authenticationManagerResolver( + ReactiveAuthenticationManagerResolver authenticationManagerResolver) { + Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null"); + this.authenticationManagerResolver = authenticationManagerResolver; + return this; + } + + /** + * Enables JWT Resource Server support. + * @return the {@link JwtSpec} for additional configuration + */ + public JwtSpec jwt() { + if (this.jwt == null) { + this.jwt = new JwtSpec(); + } + return this.jwt; + } + + /** + * Enables JWT Resource Server support. + * @param jwtCustomizer the {@link Customizer} to provide more options for the + * {@link JwtSpec} + * @return the {@link OAuth2ResourceServerSpec} to customize + */ + public OAuth2ResourceServerSpec jwt(Customizer jwtCustomizer) { + if (this.jwt == null) { + this.jwt = new JwtSpec(); + } + jwtCustomizer.customize(this.jwt); + return this; + } + + /** + * Enables Opaque Token Resource Server support. + * @return the {@link OpaqueTokenSpec} for additional configuration + */ + public OpaqueTokenSpec opaqueToken() { + if (this.opaqueToken == null) { + this.opaqueToken = new OpaqueTokenSpec(); + } + return this.opaqueToken; + } + + /** + * Enables Opaque Token Resource Server support. + * @param opaqueTokenCustomizer the {@link Customizer} to provide more options for + * the {@link OpaqueTokenSpec} + * @return the {@link OAuth2ResourceServerSpec} to customize + */ + public OAuth2ResourceServerSpec opaqueToken(Customizer opaqueTokenCustomizer) { + if (this.opaqueToken == null) { + this.opaqueToken = new OpaqueTokenSpec(); + } + opaqueTokenCustomizer.customize(this.opaqueToken); + return this; + } + + protected void configure(ServerHttpSecurity http) { + this.authenticationConverterServerWebExchangeMatcher = new AuthenticationConverterServerWebExchangeMatcher( + this.bearerTokenConverter); + + registerDefaultAccessDeniedHandler(http); + registerDefaultAuthenticationEntryPoint(http); + registerDefaultCsrfOverride(http); + + validateConfiguration(); + + if (this.authenticationManagerResolver != null) { + AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(this.authenticationManagerResolver); + oauth2.setServerAuthenticationConverter(this.bearerTokenConverter); + oauth2.setAuthenticationFailureHandler( + new ServerAuthenticationEntryPointFailureHandler(this.entryPoint)); + http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); + } + else if (this.jwt != null) { + this.jwt.configure(http); + } + else if (this.opaqueToken != null) { + this.opaqueToken.configure(http); + } + } + + private void validateConfiguration() { + if (this.authenticationManagerResolver == null) { + if (this.jwt == null && this.opaqueToken == null) { + throw new IllegalStateException( + "Jwt and Opaque Token are the only supported formats for bearer tokens " + + "in Spring Security and neither was found. Make sure to configure JWT " + + "via http.oauth2ResourceServer().jwt() or Opaque Tokens via " + + "http.oauth2ResourceServer().opaqueToken()."); + } + + if (this.jwt != null && this.opaqueToken != null) { + throw new IllegalStateException( + "Spring Security only supports JWTs or Opaque Tokens, not both at the " + "same time."); + } + } + else { + if (this.jwt != null || this.opaqueToken != null) { + throw new IllegalStateException( + "If an authenticationManagerResolver() is configured, then it takes " + + "precedence over any jwt() or opaqueToken() configuration."); + } + } + } + + private void registerDefaultAccessDeniedHandler(ServerHttpSecurity http) { + if (http.exceptionHandling != null) { + http.defaultAccessDeniedHandlers + .add(new ServerWebExchangeDelegatingServerAccessDeniedHandler.DelegateEntry( + this.authenticationConverterServerWebExchangeMatcher, + OAuth2ResourceServerSpec.this.accessDeniedHandler)); + } + } + + private void registerDefaultAuthenticationEntryPoint(ServerHttpSecurity http) { + if (http.exceptionHandling != null) { + http.defaultEntryPoints.add(new DelegateEntry(this.authenticationConverterServerWebExchangeMatcher, + OAuth2ResourceServerSpec.this.entryPoint)); + } + } + + private void registerDefaultCsrfOverride(ServerHttpSecurity http) { + if (http.csrf != null && !http.csrf.specifiedRequireCsrfProtectionMatcher) { + // @formatter:off + http + .csrf() + .requireCsrfProtectionMatcher( + new AndServerWebExchangeMatcher( + CsrfWebFilter.DEFAULT_CSRF_MATCHER, + new NegatedServerWebExchangeMatcher( + this.authenticationConverterServerWebExchangeMatcher))); + // @formatter:on + } + } + + public ServerHttpSecurity and() { + return ServerHttpSecurity.this; + } + + private class BearerTokenAuthenticationWebFilter extends AuthenticationWebFilter { + + private ServerAuthenticationFailureHandler authenticationFailureHandler; + + BearerTokenAuthenticationWebFilter(ReactiveAuthenticationManager authenticationManager) { + super(authenticationManager); + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + WebFilterExchange webFilterExchange = new WebFilterExchange(exchange, chain); + return super.filter(exchange, chain).onErrorResume(AuthenticationException.class, + e -> this.authenticationFailureHandler.onAuthenticationFailure(webFilterExchange, e)); + } + + @Override + public void setAuthenticationFailureHandler( + ServerAuthenticationFailureHandler authenticationFailureHandler) { + super.setAuthenticationFailureHandler(authenticationFailureHandler); + this.authenticationFailureHandler = authenticationFailureHandler; + } + + } + + /** + * Configures JWT Resource Server Support + */ + public class JwtSpec { + + private ReactiveAuthenticationManager authenticationManager; + + private ReactiveJwtDecoder jwtDecoder; + + private Converter> jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverterAdapter( + new JwtAuthenticationConverter()); + + /** + * Configures the {@link ReactiveAuthenticationManager} to use + * @param authenticationManager the authentication manager to use + * @return the {@code JwtSpec} for additional configuration + */ + public JwtSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) { + Assert.notNull(authenticationManager, "authenticationManager cannot be null"); + this.authenticationManager = authenticationManager; + return this; + } + + /** + * Configures the {@link Converter} to use for converting a {@link Jwt} into + * an {@link AbstractAuthenticationToken}. + * @param jwtAuthenticationConverter the converter to use + * @return the {@code JwtSpec} for additional configuration + * @since 5.1.1 + */ + public JwtSpec jwtAuthenticationConverter( + Converter> jwtAuthenticationConverter) { + Assert.notNull(jwtAuthenticationConverter, "jwtAuthenticationConverter cannot be null"); + this.jwtAuthenticationConverter = jwtAuthenticationConverter; + return this; + } + + /** + * Configures the {@link ReactiveJwtDecoder} to use + * @param jwtDecoder the decoder to use + * @return the {@code JwtSpec} for additional configuration + */ + public JwtSpec jwtDecoder(ReactiveJwtDecoder jwtDecoder) { + this.jwtDecoder = jwtDecoder; + return this; + } + + /** + * Configures a {@link ReactiveJwtDecoder} that leverages the provided + * {@link RSAPublicKey} + * @param publicKey the public key to use. + * @return the {@code JwtSpec} for additional configuration + */ + public JwtSpec publicKey(RSAPublicKey publicKey) { + this.jwtDecoder = new NimbusReactiveJwtDecoder(publicKey); + return this; + } + + /** + * Configures a {@link ReactiveJwtDecoder} using + * JSON Web Key + * (JWK) URL + * @param jwkSetUri the URL to use. + * @return the {@code JwtSpec} for additional configuration + */ + public JwtSpec jwkSetUri(String jwkSetUri) { + this.jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri); + return this; + } + + public OAuth2ResourceServerSpec and() { + return OAuth2ResourceServerSpec.this; + } + + protected void configure(ServerHttpSecurity http) { + ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); + AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager); + oauth2.setServerAuthenticationConverter(OAuth2ResourceServerSpec.this.bearerTokenConverter); + oauth2.setAuthenticationFailureHandler( + new ServerAuthenticationEntryPointFailureHandler(OAuth2ResourceServerSpec.this.entryPoint)); + // @formatter:off + http + .addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); + // @formatter:on + } + + protected ReactiveJwtDecoder getJwtDecoder() { + if (this.jwtDecoder == null) { + return getBean(ReactiveJwtDecoder.class); + } + return this.jwtDecoder; + } + + protected Converter> getJwtAuthenticationConverter() { + + return this.jwtAuthenticationConverter; + } + + private ReactiveAuthenticationManager getAuthenticationManager() { + if (this.authenticationManager != null) { + return this.authenticationManager; + } + + ReactiveJwtDecoder jwtDecoder = getJwtDecoder(); + Converter> jwtAuthenticationConverter = getJwtAuthenticationConverter(); + JwtReactiveAuthenticationManager authenticationManager = new JwtReactiveAuthenticationManager( + jwtDecoder); + authenticationManager.setJwtAuthenticationConverter(jwtAuthenticationConverter); + + return authenticationManager; + } + + } + + /** + * Configures Opaque Token Resource Server support + * + * @author Josh Cummings + * @since 5.2 + */ + public final class OpaqueTokenSpec { + + private String introspectionUri; + + private String clientId; + + private String clientSecret; + + private Supplier introspector; + + private OpaqueTokenSpec() { + } + + /** + * Configures the URI of the Introspection endpoint + * @param introspectionUri The URI of the Introspection endpoint + * @return the {@code OpaqueTokenSpec} for additional configuration + */ + public OpaqueTokenSpec introspectionUri(String introspectionUri) { + Assert.hasText(introspectionUri, "introspectionUri cannot be empty"); + this.introspectionUri = introspectionUri; + this.introspector = () -> new NimbusReactiveOpaqueTokenIntrospector(this.introspectionUri, + this.clientId, this.clientSecret); + return this; + } + + /** + * Configures the credentials for Introspection endpoint + * @param clientId The clientId part of the credentials + * @param clientSecret The clientSecret part of the credentials + * @return the {@code OpaqueTokenSpec} for additional configuration + */ + public OpaqueTokenSpec introspectionClientCredentials(String clientId, String clientSecret) { + Assert.hasText(clientId, "clientId cannot be empty"); + Assert.notNull(clientSecret, "clientSecret cannot be null"); + this.clientId = clientId; + this.clientSecret = clientSecret; + this.introspector = () -> new NimbusReactiveOpaqueTokenIntrospector(this.introspectionUri, + this.clientId, this.clientSecret); + return this; + } + + public OpaqueTokenSpec introspector(ReactiveOpaqueTokenIntrospector introspector) { + Assert.notNull(introspector, "introspector cannot be null"); + this.introspector = () -> introspector; + return this; + } + + /** + * Allows method chaining to continue configuring the + * {@link ServerHttpSecurity} + * @return the {@link ServerHttpSecurity} to continue configuring + */ + public OAuth2ResourceServerSpec and() { + return OAuth2ResourceServerSpec.this; + } + + protected ReactiveAuthenticationManager getAuthenticationManager() { + return new OpaqueTokenReactiveAuthenticationManager(getIntrospector()); + } + + protected ReactiveOpaqueTokenIntrospector getIntrospector() { + if (this.introspector != null) { + return this.introspector.get(); + } + return getBean(ReactiveOpaqueTokenIntrospector.class); + } + + protected void configure(ServerHttpSecurity http) { + ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); + AuthenticationWebFilter oauth2 = new BearerTokenAuthenticationWebFilter(authenticationManager); + oauth2.setServerAuthenticationConverter(OAuth2ResourceServerSpec.this.bearerTokenConverter); + oauth2.setAuthenticationFailureHandler( + new ServerAuthenticationEntryPointFailureHandler(OAuth2ResourceServerSpec.this.entryPoint)); + http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); + } + + } + + } + /** * Configures anonymous authentication * diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java index 2f52e4f7b5..fa6bf9e5fa 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java @@ -68,6 +68,9 @@ public class AuthenticationManagerBuilderTests { @Rule public final SpringTestRule spring = new SpringTestRule(); + @Autowired(required = false) + MockMvc mockMvc; + @Test public void buildWhenAddAuthenticationProviderThenDoesNotPerformRegistration() throws Exception { ObjectPostProcessor opp = mock(ObjectPostProcessor.class); @@ -110,25 +113,6 @@ public class AuthenticationManagerBuilderTests { assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER"); } - @EnableWebSecurity - static class PasswordEncoderGlobalConfig extends WebSecurityConfigurerAdapter { - - @Autowired - void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - // @formatter:off - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); - // @formatter:on - } - - @Bean - PasswordEncoder passwordEncoder() { - return NoOpPasswordEncoder.getInstance(); - } - - } - @Test public void getAuthenticationManagerWhenProtectedPasswordEncoderBeanThenUsed() throws Exception { this.spring.register(PasswordEncoderGlobalConfig.class).autowire(); @@ -141,28 +125,6 @@ public class AuthenticationManagerBuilderTests { assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER"); } - @EnableWebSecurity - static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - // @formatter:off - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); - // @formatter:on - } - - @Bean - PasswordEncoder passwordEncoder() { - return NoOpPasswordEncoder.getInstance(); - } - - } - - @Autowired(required = false) - MockMvc mockMvc; - @Test public void authenticationManagerWhenMultipleProvidersThenWorks() throws Exception { this.spring.register(MultiAuthenticationProvidersConfig.class).autowire(); @@ -173,17 +135,6 @@ public class AuthenticationManagerBuilderTests { .andExpect(authenticated().withUsername("admin").withRoles("USER", "ADMIN")); } - @EnableWebSecurity - static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser(PasswordEncodedUser.user()).and().inMemoryAuthentication() - .withUser(PasswordEncodedUser.admin()); - } - - } - @Test public void buildWhenAuthenticationProviderThenIsConfigured() throws Exception { ObjectPostProcessor opp = mock(ObjectPostProcessor.class); @@ -225,6 +176,55 @@ public class AuthenticationManagerBuilderTests { .andExpect(authenticated().withUsername("joe").withRoles("USER")); } + @EnableWebSecurity + static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication().withUser(PasswordEncodedUser.user()).and().inMemoryAuthentication() + .withUser(PasswordEncodedUser.admin()); + } + + } + + @EnableWebSecurity + static class PasswordEncoderGlobalConfig extends WebSecurityConfigurerAdapter { + + @Autowired + void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + // @formatter:on + } + + @Bean + PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } + + } + + @EnableWebSecurity + static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + // @formatter:on + } + + @Bean + PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } + + } + @Configuration @EnableGlobalAuthentication @Import(ObjectPostProcessorConfiguration.class) diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationManagerTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationManagerTests.java index 6aa34abb27..4f924e7878 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationManagerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationManagerTests.java @@ -53,6 +53,27 @@ public class NamespaceAuthenticationManagerTests { // no exception due to username being cleared out } + @Test + public void authenticationMangerWhenEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception { + this.spring.register(EraseCredentialsFalseConfig.class).autowire(); + + this.mockMvc.perform(formLogin()) + .andExpect(authenticated().withAuthentication(a -> assertThat(a.getCredentials()).isNotNull())); + + this.mockMvc.perform(formLogin()) + .andExpect(authenticated().withAuthentication(a -> assertThat(a.getCredentials()).isNotNull())); + // no exception due to username being cleared out + } + + @Test + // SEC-2533 + public void authenticationManagerWhenGlobalAndEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception { + this.spring.register(GlobalEraseCredentialsFalseConfig.class).autowire(); + + this.mockMvc.perform(formLogin()) + .andExpect(authenticated().withAuthentication(a -> assertThat(a.getCredentials()).isNotNull())); + } + @EnableWebSecurity static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter { @@ -67,18 +88,6 @@ public class NamespaceAuthenticationManagerTests { } - @Test - public void authenticationMangerWhenEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception { - this.spring.register(EraseCredentialsFalseConfig.class).autowire(); - - this.mockMvc.perform(formLogin()) - .andExpect(authenticated().withAuthentication(a -> assertThat(a.getCredentials()).isNotNull())); - - this.mockMvc.perform(formLogin()) - .andExpect(authenticated().withAuthentication(a -> assertThat(a.getCredentials()).isNotNull())); - // no exception due to username being cleared out - } - @EnableWebSecurity static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter { @@ -94,15 +103,6 @@ public class NamespaceAuthenticationManagerTests { } - @Test - // SEC-2533 - public void authenticationManagerWhenGlobalAndEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception { - this.spring.register(GlobalEraseCredentialsFalseConfig.class).autowire(); - - this.mockMvc.perform(formLogin()) - .andExpect(authenticated().withAuthentication(a -> assertThat(a.getCredentials()).isNotNull())); - } - @EnableWebSecurity static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter { diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationProviderTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationProviderTests.java index ed63199915..aa3853f0f6 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationProviderTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceAuthenticationProviderTests.java @@ -53,6 +53,14 @@ public class NamespaceAuthenticationProviderTests { this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user")); } + @Test + // authentication-provider@user-service-ref + public void authenticationProviderUserServiceRef() throws Exception { + this.spring.register(AuthenticationProviderRefConfig.class).autowire(); + + this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user")); + } + @EnableWebSecurity static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter { @@ -73,14 +81,6 @@ public class NamespaceAuthenticationProviderTests { } - @Test - // authentication-provider@user-service-ref - public void authenticationProviderUserServiceRef() throws Exception { - this.spring.register(AuthenticationProviderRefConfig.class).autowire(); - - this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user")); - } - @EnableWebSecurity static class UserServiceRefConfig extends WebSecurityConfigurerAdapter { diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceJdbcUserServiceTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceJdbcUserServiceTests.java index bf3c3d4994..64c6c455e2 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceJdbcUserServiceTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespaceJdbcUserServiceTests.java @@ -57,6 +57,13 @@ public class NamespaceJdbcUserServiceTests { this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user")); } + @Test + public void jdbcUserServiceCustom() throws Exception { + this.spring.register(CustomDataSourceConfig.class, CustomJdbcUserServiceSampleConfig.class).autowire(); + + this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user").withRoles("DBA", "USER")); + } + @EnableWebSecurity static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter { @@ -87,13 +94,6 @@ public class NamespaceJdbcUserServiceTests { } - @Test - public void jdbcUserServiceCustom() throws Exception { - this.spring.register(CustomDataSourceConfig.class, CustomJdbcUserServiceSampleConfig.class).autowire(); - - this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user").withRoles("DBA", "USER")); - } - @EnableWebSecurity static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter { diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespacePasswordEncoderTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespacePasswordEncoderTests.java index 1288673c9e..a535a1874b 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespacePasswordEncoderTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/NamespacePasswordEncoderTests.java @@ -56,6 +56,20 @@ public class NamespacePasswordEncoderTests { this.mockMvc.perform(formLogin()).andExpect(authenticated()); } + @Test + public void passwordEncoderRefWithJdbc() throws Exception { + this.spring.register(PasswordEncoderWithJdbcConfig.class).autowire(); + + this.mockMvc.perform(formLogin()).andExpect(authenticated()); + } + + @Test + public void passwordEncoderRefWithUserDetailsService() throws Exception { + this.spring.register(PasswordEncoderWithUserDetailsServiceConfig.class).autowire(); + + this.mockMvc.perform(formLogin()).andExpect(authenticated()); + } + @EnableWebSecurity static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter { @@ -72,13 +86,6 @@ public class NamespacePasswordEncoderTests { } - @Test - public void passwordEncoderRefWithJdbc() throws Exception { - this.spring.register(PasswordEncoderWithJdbcConfig.class).autowire(); - - this.mockMvc.perform(formLogin()).andExpect(authenticated()); - } - @EnableWebSecurity static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter { @@ -104,13 +111,6 @@ public class NamespacePasswordEncoderTests { } - @Test - public void passwordEncoderRefWithUserDetailsService() throws Exception { - this.spring.register(PasswordEncoderWithUserDetailsServiceConfig.class).autowire(); - - this.mockMvc.perform(formLogin()).andExpect(authenticated()); - } - @EnableWebSecurity static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter { diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/PasswordEncoderConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/PasswordEncoderConfigurerTests.java index 88c3464ebc..85c46ab747 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/PasswordEncoderConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/PasswordEncoderConfigurerTests.java @@ -48,6 +48,13 @@ public class PasswordEncoderConfigurerTests { this.spring.register(PasswordEncoderConfig.class).autowire(); } + @Test + public void passwordEncoderRefWhenAuthenticationManagerBuilderThenAuthenticationSuccess() throws Exception { + this.spring.register(PasswordEncoderNoAuthManagerLoadsConfig.class).autowire(); + + this.mockMvc.perform(formLogin()).andExpect(authenticated()); + } + @EnableWebSecurity static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter { @@ -73,13 +80,6 @@ public class PasswordEncoderConfigurerTests { } - @Test - public void passwordEncoderRefWhenAuthenticationManagerBuilderThenAuthenticationSuccess() throws Exception { - this.spring.register(PasswordEncoderNoAuthManagerLoadsConfig.class).autowire(); - - this.mockMvc.perform(formLogin()).andExpect(authenticated()); - } - @EnableWebSecurity static class PasswordEncoderNoAuthManagerLoadsConfig extends WebSecurityConfigurerAdapter { diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java index d42c638cb3..e091dcecb1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java @@ -93,11 +93,6 @@ public class AuthenticationConfigurationTests { this.service.run(); } - @EnableGlobalMethodSecurity(securedEnabled = true) - static class GlobalMethodSecurityAutowiredConfig { - - } - @Test public void orderingAutowiredOnEnableWebSecurity() { this.spring.register(AuthenticationTestConfiguration.class, WebSecurityConfig.class, @@ -108,11 +103,6 @@ public class AuthenticationConfigurationTests { this.service.run(); } - @EnableWebSecurity - static class WebSecurityConfig { - - } - @Test public void orderingAutowiredOnEnableWebMvcSecurity() { this.spring.register(AuthenticationTestConfiguration.class, WebMvcSecurityConfig.class, @@ -123,11 +113,6 @@ public class AuthenticationConfigurationTests { this.service.run(); } - @EnableWebMvcSecurity - static class WebMvcSecurityConfig { - - } - @Test public void getAuthenticationManagerWhenNoAuthenticationThenNull() throws Exception { this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire(); @@ -145,11 +130,6 @@ public class AuthenticationConfigurationTests { .isNull(); } - @Configuration - static class NoOpGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { - - } - @Test public void getAuthenticationWhenGlobalAuthenticationConfigurerAdapterThenAuthenticates() throws Exception { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password"); @@ -162,16 +142,6 @@ public class AuthenticationConfigurationTests { assertThat(authentication.authenticate(token).getName()).isEqualTo(token.getName()); } - @Configuration - static class UserGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { - - @Override - public void init(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser(PasswordEncodedUser.user()); - } - - } - @Test public void getAuthenticationWhenAuthenticationManagerBeanThenAuthenticates() throws Exception { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password"); @@ -185,6 +155,200 @@ public class AuthenticationConfigurationTests { assertThat(authentication.authenticate(token).getName()).isEqualTo(token.getName()); } + @Test + public void getAuthenticationWhenMultipleThenOrdered() throws Exception { + this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, + AuthenticationManagerBeanConfig.class).autowire(); + AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); + config.setGlobalAuthenticationConfigurers(Arrays.asList(new LowestOrderGlobalAuthenticationConfigurerAdapter(), + new HighestOrderGlobalAuthenticationConfigurerAdapter(), + new DefaultOrderGlobalAuthenticationConfigurerAdapter())); + } + + @Test + public void getAuthenticationWhenConfiguredThenBootNotTrigger() throws Exception { + this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire(); + AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); + config.setGlobalAuthenticationConfigurers(Arrays.asList(new ConfiguresInMemoryConfigurerAdapter(), + new BootGlobalAuthenticationConfigurerAdapter())); + AuthenticationManager authenticationManager = config.getAuthenticationManager(); + + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + + assertThatThrownBy( + () -> authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password"))) + .isInstanceOf(AuthenticationException.class); + + } + + @Test + public void getAuthenticationWhenNotConfiguredThenBootTrigger() throws Exception { + this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire(); + AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); + config.setGlobalAuthenticationConfigurers(Arrays.asList(new BootGlobalAuthenticationConfigurerAdapter())); + AuthenticationManager authenticationManager = config.getAuthenticationManager(); + + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password")); + } + + // gh-2531 + @Test + public void getAuthenticationManagerWhenPostProcessThenUsesBeanClassLoaderOnProxyFactoryBean() throws Exception { + this.spring.register(Sec2531Config.class).autowire(); + ObjectPostProcessor opp = this.spring.getContext().getBean(ObjectPostProcessor.class); + when(opp.postProcess(any())).thenAnswer(a -> a.getArgument(0)); + + AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); + config.getAuthenticationManager(); + + verify(opp).postProcess(any(ProxyFactoryBean.class)); + } + + @Test + public void getAuthenticationManagerWhenSec2822ThenCannotForceAuthenticationAlreadyBuilt() throws Exception { + this.spring.register(Sec2822WebSecurity.class, Sec2822UseAuth.class, Sec2822Config.class).autowire(); + + this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager(); + // no exception + } + + // sec-2868 + @Test + public void getAuthenticationWhenUserDetailsServiceBeanThenAuthenticationManagerUsesUserDetailsServiceBean() + throws Exception { + this.spring.register(UserDetailsServiceBeanConfig.class).autowire(); + UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class); + AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) + .getAuthenticationManager(); + when(uds.loadUserByUsername("user")).thenReturn(PasswordEncodedUser.user(), PasswordEncodedUser.user()); + + am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + + assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid"))) + .isInstanceOf(AuthenticationException.class); + } + + @Test + public void getAuthenticationWhenUserDetailsServiceAndPasswordEncoderBeanThenEncoderUsed() throws Exception { + UserDetails user = new User("user", "$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u", + AuthorityUtils.createAuthorityList("ROLE_USER")); + this.spring.register(UserDetailsServiceBeanWithPasswordEncoderConfig.class).autowire(); + UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class); + AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) + .getAuthenticationManager(); + when(uds.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), + User.withUserDetails(user).build()); + + am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + + assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid"))) + .isInstanceOf(AuthenticationException.class); + } + + @Test + public void getAuthenticationWhenUserDetailsServiceAndPasswordManagerThenManagerUsed() throws Exception { + UserDetails user = new User("user", "{noop}password", AuthorityUtils.createAuthorityList("ROLE_USER")); + this.spring.register(UserDetailsPasswordManagerBeanConfig.class).autowire(); + UserDetailsPasswordManagerBeanConfig.Manager manager = this.spring.getContext() + .getBean(UserDetailsPasswordManagerBeanConfig.Manager.class); + AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) + .getAuthenticationManager(); + when(manager.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), + User.withUserDetails(user).build()); + when(manager.updatePassword(any(), any())).thenReturn(user); + + am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + + verify(manager).updatePassword(eq(user), startsWith("{bcrypt}")); + } + + @Test + public void getAuthenticationWhenAuthenticationProviderAndUserDetailsBeanThenAuthenticationProviderUsed() + throws Exception { + this.spring.register(AuthenticationProviderBeanAndUserDetailsServiceConfig.class).autowire(); + AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class); + AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) + .getAuthenticationManager(); + when(ap.supports(any())).thenReturn(true); + when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser()); + + am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + } + + // gh-3091 + @Test + public void getAuthenticationWhenAuthenticationProviderBeanThenUsed() throws Exception { + this.spring.register(AuthenticationProviderBeanConfig.class).autowire(); + AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class); + AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) + .getAuthenticationManager(); + when(ap.supports(any())).thenReturn(true); + when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser()); + + am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + } + + @Test + public void enableGlobalMethodSecurityWhenPreAuthorizeThenNoException() { + this.spring.register(UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class) + .autowire(); + // no exception + } + + @Test + public void enableGlobalMethodSecurityWhenPreAuthorizeThenUsesMethodSecurityService() { + this.spring.register(ServicesConfig.class, UsesPreAuthorizeMethodSecurityConfig.class, + AuthenticationManagerBeanConfig.class).autowire(); + // no exception + } + + @Test + public void getAuthenticationManagerBeanWhenMultipleDefinedAndOnePrimaryThenNoException() throws Exception { + this.spring.register(MultipleAuthenticationManagerBeanConfig.class).autowire(); + this.spring.getContext().getBeanFactory().getBean(AuthenticationConfiguration.class).getAuthenticationManager(); + } + + @Test + public void getAuthenticationManagerWhenAuthenticationConfigurationSubclassedThenBuildsUsingBean() + throws Exception { + this.spring.register(AuthenticationConfigurationSubclass.class).autowire(); + AuthenticationManagerBuilder ap = this.spring.getContext().getBean(AuthenticationManagerBuilder.class); + + this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager(); + + assertThatThrownBy(ap::build).isInstanceOf(AlreadyBuiltException.class); + } + + @EnableGlobalMethodSecurity(securedEnabled = true) + static class GlobalMethodSecurityAutowiredConfig { + + } + + @EnableWebSecurity + static class WebSecurityConfig { + + } + + @EnableWebMvcSecurity + static class WebMvcSecurityConfig { + + } + + @Configuration + static class NoOpGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { + + } + + @Configuration + static class UserGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { + + @Override + public void init(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication().withUser(PasswordEncodedUser.user()); + } + + } + @Configuration static class AuthenticationManagerBeanConfig { @@ -197,9 +361,6 @@ public class AuthenticationConfigurationTests { } - // - // // - // @Configuration static class ServicesConfig { @@ -225,16 +386,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationWhenMultipleThenOrdered() throws Exception { - this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, - AuthenticationManagerBeanConfig.class).autowire(); - AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); - config.setGlobalAuthenticationConfigurers(Arrays.asList(new LowestOrderGlobalAuthenticationConfigurerAdapter(), - new HighestOrderGlobalAuthenticationConfigurerAdapter(), - new DefaultOrderGlobalAuthenticationConfigurerAdapter())); - } - static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { static List> inits = new ArrayList<>(); @@ -264,32 +415,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationWhenConfiguredThenBootNotTrigger() throws Exception { - this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire(); - AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); - config.setGlobalAuthenticationConfigurers(Arrays.asList(new ConfiguresInMemoryConfigurerAdapter(), - new BootGlobalAuthenticationConfigurerAdapter())); - AuthenticationManager authenticationManager = config.getAuthenticationManager(); - - authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); - - assertThatThrownBy( - () -> authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password"))) - .isInstanceOf(AuthenticationException.class); - - } - - @Test - public void getAuthenticationWhenNotConfiguredThenBootTrigger() throws Exception { - this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire(); - AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); - config.setGlobalAuthenticationConfigurers(Arrays.asList(new BootGlobalAuthenticationConfigurerAdapter())); - AuthenticationManager authenticationManager = config.getAuthenticationManager(); - - authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password")); - } - static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { @Override @@ -335,19 +460,6 @@ public class AuthenticationConfigurationTests { } - // gh-2531 - @Test - public void getAuthenticationManagerWhenPostProcessThenUsesBeanClassLoaderOnProxyFactoryBean() throws Exception { - this.spring.register(Sec2531Config.class).autowire(); - ObjectPostProcessor opp = this.spring.getContext().getBean(ObjectPostProcessor.class); - when(opp.postProcess(any())).thenAnswer(a -> a.getArgument(0)); - - AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class); - config.getAuthenticationManager(); - - verify(opp).postProcess(any(ProxyFactoryBean.class)); - } - @Configuration @Import(AuthenticationConfiguration.class) static class Sec2531Config { @@ -364,14 +476,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationManagerWhenSec2822ThenCannotForceAuthenticationAlreadyBuilt() throws Exception { - this.spring.register(Sec2822WebSecurity.class, Sec2822UseAuth.class, Sec2822Config.class).autowire(); - - this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager(); - // no exception - } - @Configuration @Import(AuthenticationConfiguration.class) static class Sec2822Config { @@ -410,22 +514,6 @@ public class AuthenticationConfigurationTests { } - // sec-2868 - @Test - public void getAuthenticationWhenUserDetailsServiceBeanThenAuthenticationManagerUsesUserDetailsServiceBean() - throws Exception { - this.spring.register(UserDetailsServiceBeanConfig.class).autowire(); - UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class); - AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) - .getAuthenticationManager(); - when(uds.loadUserByUsername("user")).thenReturn(PasswordEncodedUser.user(), PasswordEncodedUser.user()); - - am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); - - assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid"))) - .isInstanceOf(AuthenticationException.class); - } - @Configuration @Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class }) static class UserDetailsServiceBeanConfig { @@ -439,23 +527,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationWhenUserDetailsServiceAndPasswordEncoderBeanThenEncoderUsed() throws Exception { - UserDetails user = new User("user", "$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u", - AuthorityUtils.createAuthorityList("ROLE_USER")); - this.spring.register(UserDetailsServiceBeanWithPasswordEncoderConfig.class).autowire(); - UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class); - AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) - .getAuthenticationManager(); - when(uds.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), - User.withUserDetails(user).build()); - - am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); - - assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid"))) - .isInstanceOf(AuthenticationException.class); - } - @Configuration @Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class }) static class UserDetailsServiceBeanWithPasswordEncoderConfig { @@ -474,23 +545,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationWhenUserDetailsServiceAndPasswordManagerThenManagerUsed() throws Exception { - UserDetails user = new User("user", "{noop}password", AuthorityUtils.createAuthorityList("ROLE_USER")); - this.spring.register(UserDetailsPasswordManagerBeanConfig.class).autowire(); - UserDetailsPasswordManagerBeanConfig.Manager manager = this.spring.getContext() - .getBean(UserDetailsPasswordManagerBeanConfig.Manager.class); - AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) - .getAuthenticationManager(); - when(manager.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), - User.withUserDetails(user).build()); - when(manager.updatePassword(any(), any())).thenReturn(user); - - am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); - - verify(manager).updatePassword(eq(user), startsWith("{bcrypt}")); - } - @Configuration @Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class }) static class UserDetailsPasswordManagerBeanConfig { @@ -508,19 +562,6 @@ public class AuthenticationConfigurationTests { } - // gh-3091 - @Test - public void getAuthenticationWhenAuthenticationProviderBeanThenUsed() throws Exception { - this.spring.register(AuthenticationProviderBeanConfig.class).autowire(); - AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class); - AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) - .getAuthenticationManager(); - when(ap.supports(any())).thenReturn(true); - when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser()); - - am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); - } - @Configuration @Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class }) static class AuthenticationProviderBeanConfig { @@ -534,19 +575,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationWhenAuthenticationProviderAndUserDetailsBeanThenAuthenticationProviderUsed() - throws Exception { - this.spring.register(AuthenticationProviderBeanAndUserDetailsServiceConfig.class).autowire(); - AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class); - AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class) - .getAuthenticationManager(); - when(ap.supports(any())).thenReturn(true); - when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser()); - - am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); - } - @Configuration @Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class }) static class AuthenticationProviderBeanAndUserDetailsServiceConfig { @@ -567,14 +595,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void enableGlobalMethodSecurityWhenPreAuthorizeThenNoException() { - this.spring.register(UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class) - .autowire(); - - // no exception - } - @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) static class UsesPreAuthorizeMethodSecurityConfig { @@ -585,14 +605,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void enableGlobalMethodSecurityWhenPreAuthorizeThenUsesMethodSecurityService() { - this.spring.register(ServicesConfig.class, UsesPreAuthorizeMethodSecurityConfig.class, - AuthenticationManagerBeanConfig.class).autowire(); - - // no exception - } - @Configuration @EnableGlobalMethodSecurity(securedEnabled = true) static class UsesServiceMethodSecurityConfig { @@ -602,12 +614,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationManagerBeanWhenMultipleDefinedAndOnePrimaryThenNoException() throws Exception { - this.spring.register(MultipleAuthenticationManagerBeanConfig.class).autowire(); - this.spring.getContext().getBeanFactory().getBean(AuthenticationConfiguration.class).getAuthenticationManager(); - } - @Configuration @Import(AuthenticationConfiguration.class) static class MultipleAuthenticationManagerBeanConfig { @@ -625,17 +631,6 @@ public class AuthenticationConfigurationTests { } - @Test - public void getAuthenticationManagerWhenAuthenticationConfigurationSubclassedThenBuildsUsingBean() - throws Exception { - this.spring.register(AuthenticationConfigurationSubclass.class).autowire(); - AuthenticationManagerBuilder ap = this.spring.getContext().getBean(AuthenticationManagerBuilder.class); - - this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager(); - - assertThatThrownBy(ap::build).isInstanceOf(AlreadyBuiltException.class); - } - @Configuration static class AuthenticationConfigurationSubclass extends AuthenticationConfiguration { diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/EnableGlobalAuthenticationTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/EnableGlobalAuthenticationTests.java index c36a69936c..b854bd952f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/EnableGlobalAuthenticationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/EnableGlobalAuthenticationTests.java @@ -45,6 +45,26 @@ public class EnableGlobalAuthenticationTests { assertThat(auth.getAuthenticationManager()).isNotNull(); } + @Test + public void enableGlobalAuthenticationWhenNoConfigurationAnnotationThenBeanProxyingEnabled() { + this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire(); + + Child childBean = this.spring.getContext().getBean(Child.class); + Parent parentBean = this.spring.getContext().getBean(Parent.class); + + assertThat(parentBean.getChild()).isSameAs(childBean); + } + + @Test + public void enableGlobalAuthenticationWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() { + this.spring.register(BeanProxyDisabledConfig.class).autowire(); + + Child childBean = this.spring.getContext().getBean(Child.class); + Parent parentBean = this.spring.getContext().getBean(Parent.class); + + assertThat(parentBean.getChild()).isNotSameAs(childBean); + } + @Configuration @EnableGlobalAuthentication static class Config { @@ -56,16 +76,6 @@ public class EnableGlobalAuthenticationTests { } - @Test - public void enableGlobalAuthenticationWhenNoConfigurationAnnotationThenBeanProxyingEnabled() { - this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire(); - - Child childBean = this.spring.getContext().getBean(Child.class); - Parent parentBean = this.spring.getContext().getBean(Parent.class); - - assertThat(parentBean.getChild()).isSameAs(childBean); - } - @EnableGlobalAuthentication static class BeanProxyEnabledByDefaultConfig { @@ -81,16 +91,6 @@ public class EnableGlobalAuthenticationTests { } - @Test - public void enableGlobalAuthenticationWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() { - this.spring.register(BeanProxyDisabledConfig.class).autowire(); - - Child childBean = this.spring.getContext().getBean(Child.class); - Parent parentBean = this.spring.getContext().getBean(Parent.class); - - assertThat(parentBean.getChild()).isNotSameAs(childBean); - } - @Configuration(proxyBeanMethods = false) @EnableGlobalAuthentication static class BeanProxyDisabledConfig { diff --git a/config/src/test/java/org/springframework/security/config/annotation/configuration/AutowireBeanFactoryObjectPostProcessorTests.java b/config/src/test/java/org/springframework/security/config/annotation/configuration/AutowireBeanFactoryObjectPostProcessorTests.java index 5c93b35afb..c24f59a092 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/configuration/AutowireBeanFactoryObjectPostProcessorTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/configuration/AutowireBeanFactoryObjectPostProcessorTests.java @@ -126,6 +126,25 @@ public class AutowireBeanFactoryObjectPostProcessorTests { verify(toPostProcess).destroy(); } + @Test + public void postProcessWhenSmartInitializingSingletonThenAwareInvoked() { + this.spring.register(Config.class, SmartConfig.class).autowire(); + + SmartConfig config = this.spring.getContext().getBean(SmartConfig.class); + + verify(config.toTest).afterSingletonsInstantiated(); + } + + @Test + // SEC-2382 + public void autowireBeanFactoryWhenBeanNameAutoProxyCreatorThenWorks() { + this.spring.testConfigLocations("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml").autowire(); + + MyAdvisedBean bean = this.spring.getContext().getBean(MyAdvisedBean.class); + + assertThat(bean.doStuff()).isEqualTo("null"); + } + @Configuration static class Config { @@ -136,15 +155,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests { } - @Test - public void postProcessWhenSmartInitializingSingletonThenAwareInvoked() { - this.spring.register(Config.class, SmartConfig.class).autowire(); - - SmartConfig config = this.spring.getContext().getBean(SmartConfig.class); - - verify(config.toTest).afterSingletonsInstantiated(); - } - @Configuration static class SmartConfig { @@ -157,16 +167,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests { } - @Test - // SEC-2382 - public void autowireBeanFactoryWhenBeanNameAutoProxyCreatorThenWorks() { - this.spring.testConfigLocations("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml").autowire(); - - MyAdvisedBean bean = this.spring.getContext().getBean(MyAdvisedBean.class); - - assertThat(bean.doStuff()).isEqualTo("null"); - } - @Configuration static class WithBeanNameAutoProxyCreatorConfig { diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java index 93f787f010..697f72734a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java @@ -101,27 +101,11 @@ public class GlobalMethodSecurityConfigurationTests { this.spring.register(IllegalStateGlobalMethodSecurityConfig.class).autowire(); } - @EnableGlobalMethodSecurity - public static class IllegalStateGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration { - - } - @Test public void configureWhenGlobalMethodSecurityHasCustomMetadataSourceThenNoEnablingAttributeIsNeeded() { this.spring.register(CustomMetadataSourceConfig.class).autowire(); } - @EnableGlobalMethodSecurity - public static class CustomMetadataSourceConfig extends GlobalMethodSecurityConfiguration { - - @Bean - @Override - protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() { - return mock(MethodSecurityMetadataSource.class); - } - - } - @Test public void methodSecurityAuthenticationManagerPublishesEvent() { this.spring.register(InMemoryAuthWithGlobalMethodSecurityConfig.class).autowire(); @@ -136,25 +120,6 @@ public class GlobalMethodSecurityConfigurationTests { .containsOnly((Class) AuthenticationFailureBadCredentialsEvent.class); } - @EnableGlobalMethodSecurity(prePostEnabled = true) - public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration { - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - // @formatter:off - auth - .inMemoryAuthentication(); - // @formatter:on - } - - @Bean - public MockEventListener listener() { - return new MockEventListener() { - }; - } - - } - @Test @WithMockUser public void methodSecurityWhenAuthenticationTrustResolverIsBeanThenAutowires() { @@ -170,21 +135,6 @@ public class GlobalMethodSecurityConfigurationTests { verify(trustResolver, atLeastOnce()).isAnonymous(any()); } - @EnableGlobalMethodSecurity(prePostEnabled = true) - static class CustomTrustResolverConfig { - - @Bean - public AuthenticationTrustResolver trustResolver() { - return mock(AuthenticationTrustResolver.class); - } - - @Bean - public MethodSecurityServiceImpl service() { - return new MethodSecurityServiceImpl(); - } - - } - // SEC-2301 @Test @WithMockUser @@ -197,21 +147,6 @@ public class GlobalMethodSecurityConfigurationTests { this.service.preAuthorizeBean(true); } - @EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) - static class ExpressionHandlerHasBeanResolverSetConfig { - - @Bean - public MethodSecurityServiceImpl service() { - return new MethodSecurityServiceImpl(); - } - - @Bean - public Authz authz() { - return new Authz(); - } - - } - @Test @WithMockUser public void methodSecuritySupportsAnnotaitonsOnInterfaceParamerNames() { @@ -223,16 +158,6 @@ public class GlobalMethodSecurityConfigurationTests { // no exception } - @EnableGlobalMethodSecurity(prePostEnabled = true) - static class MethodSecurityServiceConfig { - - @Bean - public MethodSecurityService service() { - return new MethodSecurityServiceImpl(); - } - - } - @Test @WithMockUser public void globalMethodSecurityConfigurationAutowiresPermissionEvaluator() { @@ -246,21 +171,6 @@ public class GlobalMethodSecurityConfigurationTests { assertThatThrownBy(() -> this.service.hasPermission("something")).isInstanceOf(AccessDeniedException.class); } - @EnableGlobalMethodSecurity(prePostEnabled = true) - public static class AutowirePermissionEvaluatorConfig { - - @Bean - public PermissionEvaluator permissionEvaluator() { - return mock(PermissionEvaluator.class); - } - - @Bean - public MethodSecurityService service() { - return new MethodSecurityServiceImpl(); - } - - } - @Test public void multiPermissionEvaluatorConfig() { this.spring.register(MultiPermissionEvaluatorConfig.class).autowire(); @@ -268,21 +178,6 @@ public class GlobalMethodSecurityConfigurationTests { // no exception } - @EnableGlobalMethodSecurity(prePostEnabled = true) - public static class MultiPermissionEvaluatorConfig { - - @Bean - public PermissionEvaluator permissionEvaluator() { - return mock(PermissionEvaluator.class); - } - - @Bean - public PermissionEvaluator permissionEvaluator2() { - return mock(PermissionEvaluator.class); - } - - } - // SEC-2425 @Test @WithMockUser @@ -292,21 +187,6 @@ public class GlobalMethodSecurityConfigurationTests { assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); } - @Configuration - static class ChildConfig extends ParentConfig { - - } - - @EnableGlobalMethodSecurity(prePostEnabled = true) - static class ParentConfig { - - @Bean - public MethodSecurityService service() { - return new MethodSecurityServiceImpl(); - } - - } - // SEC-2479 @Test @WithMockUser @@ -325,6 +205,221 @@ public class GlobalMethodSecurityConfigurationTests { } } + @Test + public void enableGlobalMethodSecurityDoesNotTriggerEagerInitializationOfBeansInGlobalAuthenticationConfigurer() { + this.spring.register(Sec2815Config.class).autowire(); + + MockBeanPostProcessor pp = this.spring.getContext().getBean(MockBeanPostProcessor.class); + + assertThat(pp.beforeInit).containsKeys("dataSource"); + assertThat(pp.afterInit).containsKeys("dataSource"); + } + + // SEC-3045 + @Test + public void globalSecurityProxiesSecurity() { + this.spring.register(Sec3005Config.class).autowire(); + + assertThat(this.service.getClass()).matches(c -> !Proxy.isProxyClass(c), "is not proxy class"); + } + // + // // gh-3797 + // def preAuthorizeBeanSpel() { + // setup: + // SecurityContextHolder.getContext().setAuthentication( + // new TestingAuthenticationToken("user", "password","ROLE_USER")) + // context = new AnnotationConfigApplicationContext(PreAuthorizeBeanSpelConfig) + // BeanSpelService service = context.getBean(BeanSpelService) + // when: + // service.run(true) + // then: + // noExceptionThrown() + // when: + // service.run(false) + // then: + // thrown(AccessDeniedException) + // } + // + + @Test + @WithMockUser + public void preAuthorizeBeanSpel() { + this.spring.register(PreAuthorizeBeanSpelConfig.class).autowire(); + + assertThatThrownBy(() -> this.service.preAuthorizeBean(false)).isInstanceOf(AccessDeniedException.class); + + this.service.preAuthorizeBean(true); + } + + // gh-3394 + @Test + @WithMockUser + public void roleHierarchy() { + this.spring.register(RoleHierarchyConfig.class).autowire(); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + this.service.preAuthorizeAdmin(); + } + + @Test + @WithMockUser(authorities = "ROLE:USER") + public void grantedAuthorityDefaultsAutowires() { + this.spring.register(CustomGrantedAuthorityConfig.class).autowire(); + + CustomGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext() + .getBean(CustomGrantedAuthorityConfig.CustomAuthorityService.class); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + + customService.customPrefixRoleUser(); + // no exception + } + + @Test + @WithMockUser(authorities = "USER") + public void grantedAuthorityDefaultsWithEmptyRolePrefix() { + this.spring.register(EmptyRolePrefixGrantedAuthorityConfig.class).autowire(); + + EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext() + .getBean(EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService.class); + + assertThatThrownBy(() -> this.service.securedUser()).isInstanceOf(AccessDeniedException.class); + + customService.emptyPrefixRoleUser(); + // no exception + } + + @Test + public void methodSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() { + this.spring.register(CustomMetadataSourceBeanProxyEnabledConfig.class).autowire(); + MethodSecurityInterceptor methodInterceptor = (MethodSecurityInterceptor) this.spring.getContext() + .getBean(MethodInterceptor.class); + MethodSecurityMetadataSource methodSecurityMetadataSource = this.spring.getContext() + .getBean(MethodSecurityMetadataSource.class); + + assertThat(methodInterceptor.getSecurityMetadataSource()).isSameAs(methodSecurityMetadataSource); + } + + @EnableGlobalMethodSecurity + public static class IllegalStateGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration { + + } + + @EnableGlobalMethodSecurity + public static class CustomMetadataSourceConfig extends GlobalMethodSecurityConfiguration { + + @Bean + @Override + protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() { + return mock(MethodSecurityMetadataSource.class); + } + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true) + public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication(); + // @formatter:on + } + + @Bean + public MockEventListener listener() { + return new MockEventListener() { + }; + } + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true) + static class CustomTrustResolverConfig { + + @Bean + public AuthenticationTrustResolver trustResolver() { + return mock(AuthenticationTrustResolver.class); + } + + @Bean + public MethodSecurityServiceImpl service() { + return new MethodSecurityServiceImpl(); + } + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) + static class ExpressionHandlerHasBeanResolverSetConfig { + + @Bean + public MethodSecurityServiceImpl service() { + return new MethodSecurityServiceImpl(); + } + + @Bean + public Authz authz() { + return new Authz(); + } + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true) + static class MethodSecurityServiceConfig { + + @Bean + public MethodSecurityService service() { + return new MethodSecurityServiceImpl(); + } + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true) + public static class AutowirePermissionEvaluatorConfig { + + @Bean + public PermissionEvaluator permissionEvaluator() { + return mock(PermissionEvaluator.class); + } + + @Bean + public MethodSecurityService service() { + return new MethodSecurityServiceImpl(); + } + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true) + public static class MultiPermissionEvaluatorConfig { + + @Bean + public PermissionEvaluator permissionEvaluator() { + return mock(PermissionEvaluator.class); + } + + @Bean + public PermissionEvaluator permissionEvaluator2() { + return mock(PermissionEvaluator.class); + } + + } + + @Configuration + static class ChildConfig extends ParentConfig { + + } + + @EnableGlobalMethodSecurity(prePostEnabled = true) + static class ParentConfig { + + @Bean + public MethodSecurityService service() { + return new MethodSecurityServiceImpl(); + } + + } + @Configuration static class Sec2479ParentConfig { @@ -345,16 +440,6 @@ public class GlobalMethodSecurityConfigurationTests { } - @Test - public void enableGlobalMethodSecurityDoesNotTriggerEagerInitializationOfBeansInGlobalAuthenticationConfigurer() { - this.spring.register(Sec2815Config.class).autowire(); - - MockBeanPostProcessor pp = this.spring.getContext().getBean(MockBeanPostProcessor.class); - - assertThat(pp.beforeInit).containsKeys("dataSource"); - assertThat(pp.afterInit).containsKeys("dataSource"); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) static class Sec2815Config { @@ -408,14 +493,6 @@ public class GlobalMethodSecurityConfigurationTests { } - // SEC-3045 - @Test - public void globalSecurityProxiesSecurity() { - this.spring.register(Sec3005Config.class).autowire(); - - assertThat(this.service.getClass()).matches(c -> !Proxy.isProxyClass(c), "is not proxy class"); - } - @EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ) @EnableTransactionManagement static class Sec3005Config { @@ -432,35 +509,6 @@ public class GlobalMethodSecurityConfigurationTests { } - // - // // gh-3797 - // def preAuthorizeBeanSpel() { - // setup: - // SecurityContextHolder.getContext().setAuthentication( - // new TestingAuthenticationToken("user", "password","ROLE_USER")) - // context = new AnnotationConfigApplicationContext(PreAuthorizeBeanSpelConfig) - // BeanSpelService service = context.getBean(BeanSpelService) - // when: - // service.run(true) - // then: - // noExceptionThrown() - // when: - // service.run(false) - // then: - // thrown(AccessDeniedException) - // } - // - - @Test - @WithMockUser - public void preAuthorizeBeanSpel() { - this.spring.register(PreAuthorizeBeanSpelConfig.class).autowire(); - - assertThatThrownBy(() -> this.service.preAuthorizeBean(false)).isInstanceOf(AccessDeniedException.class); - - this.service.preAuthorizeBean(true); - } - @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public static class PreAuthorizeBeanSpelConfig { @@ -477,16 +525,6 @@ public class GlobalMethodSecurityConfigurationTests { } - // gh-3394 - @Test - @WithMockUser - public void roleHierarchy() { - this.spring.register(RoleHierarchyConfig.class).autowire(); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - this.service.preAuthorizeAdmin(); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) @Configuration public static class RoleHierarchyConfig { @@ -505,20 +543,6 @@ public class GlobalMethodSecurityConfigurationTests { } - @Test - @WithMockUser(authorities = "ROLE:USER") - public void grantedAuthorityDefaultsAutowires() { - this.spring.register(CustomGrantedAuthorityConfig.class).autowire(); - - CustomGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext() - .getBean(CustomGrantedAuthorityConfig.CustomAuthorityService.class); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - - customService.customPrefixRoleUser(); - // no exception - } - @EnableGlobalMethodSecurity(prePostEnabled = true) static class CustomGrantedAuthorityConfig { @@ -547,20 +571,6 @@ public class GlobalMethodSecurityConfigurationTests { } - @Test - @WithMockUser(authorities = "USER") - public void grantedAuthorityDefaultsWithEmptyRolePrefix() { - this.spring.register(EmptyRolePrefixGrantedAuthorityConfig.class).autowire(); - - EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext() - .getBean(EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService.class); - - assertThatThrownBy(() -> this.service.securedUser()).isInstanceOf(AccessDeniedException.class); - - customService.emptyPrefixRoleUser(); - // no exception - } - @EnableGlobalMethodSecurity(securedEnabled = true) static class EmptyRolePrefixGrantedAuthorityConfig { @@ -589,17 +599,6 @@ public class GlobalMethodSecurityConfigurationTests { } - @Test - public void methodSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() { - this.spring.register(CustomMetadataSourceBeanProxyEnabledConfig.class).autowire(); - MethodSecurityInterceptor methodInterceptor = (MethodSecurityInterceptor) this.spring.getContext() - .getBean(MethodInterceptor.class); - MethodSecurityMetadataSource methodSecurityMetadataSource = this.spring.getContext() - .getBean(MethodSecurityMetadataSource.class); - - assertThat(methodInterceptor.getSecurityMetadataSource()).isSameAs(methodSecurityMetadataSource); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) @Configuration public static class CustomMetadataSourceBeanProxyEnabledConfig extends GlobalMethodSecurityConfiguration { diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java index ccfc66ac40..49a0b080cb 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java @@ -73,8 +73,6 @@ public class NamespaceGlobalMethodSecurityTests { @Autowired(required = false) private MethodSecurityService service; - // --- access-decision-manager-ref --- - @Test @WithMockUser public void methodSecurityWhenCustomAccessDecisionManagerThenAuthorizes() { @@ -86,6 +84,198 @@ public class NamespaceGlobalMethodSecurityTests { } + @Test + @WithMockUser + public void methodSecurityWhenCustomAfterInvocationManagerThenAuthorizes() { + this.spring.register(CustomAfterInvocationManagerConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatThrownBy(() -> this.service.preAuthorizePermitAll()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenCustomAuthenticationManagerThenAuthorizes() { + this.spring.register(CustomAuthenticationConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenJsr250EnabledThenAuthorizes() { + this.spring.register(Jsr250Config.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatCode(() -> this.service.preAuthorize()).doesNotThrowAnyException(); + + assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); + + assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(AccessDeniedException.class); + + assertThatCode(() -> this.service.jsr250PermitAll()).doesNotThrowAnyException(); + + } + + @Test + @WithMockUser + public void methodSecurityWhenCustomMethodSecurityMetadataSourceThenAuthorizes() { + this.spring.register(CustomMethodSecurityMetadataSourceConfig.class, MethodSecurityServiceConfig.class) + .autowire(); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + + assertThatThrownBy(() -> this.service.secured()).isInstanceOf(AccessDeniedException.class); + + assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void contextRefreshWhenUsingAspectJThenAutowire() throws Exception { + this.spring.register(AspectJModeConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThat(this.spring.getContext().getBean( + Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"))) + .isNotNull(); + assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull(); + + // TODO diagnose why aspectj isn't weaving method security advice around + // MethodSecurityServiceImpl + } + + @Test + public void contextRefreshWhenUsingAspectJAndCustomGlobalMethodSecurityConfigurationThenAutowire() + throws Exception { + + this.spring.register(AspectJModeExtendsGMSCConfig.class).autowire(); + + assertThat(this.spring.getContext().getBean( + Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"))) + .isNotNull(); + assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull(); + + } + + @Test + @WithMockUser + public void methodSecurityWhenOrderSpecifiedThenConfigured() { + this.spring.register(CustomOrderConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class) + .getOrder()).isEqualTo(-135); + + assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenOrderUnspecifiedThenConfiguredToLowestPrecedence() { + this.spring.register(DefaultOrderConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class) + .getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE); + + assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenOrderUnspecifiedAndCustomGlobalMethodSecurityConfigurationThenConfiguredToLowestPrecedence() { + this.spring.register(DefaultOrderExtendsMethodSecurityConfig.class, MethodSecurityServiceConfig.class) + .autowire(); + + assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class) + .getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE); + + assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenPrePostEnabledThenPreAuthorizes() { + this.spring.register(PreAuthorizeConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); + + assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenPrePostEnabledAndCustomGlobalMethodSecurityConfigurationThenPreAuthorizes() { + this.spring.register(PreAuthorizeExtendsGMSCConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); + + assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenProxyTargetClassThenDoesNotWireToInterface() { + this.spring.register(ProxyTargetClassConfig.class, MethodSecurityServiceConfig.class).autowire(); + + // make sure service was actually proxied + assertThat(this.service.getClass().getInterfaces()).doesNotContain(MethodSecurityService.class); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenDefaultProxyThenWiresToInterface() { + this.spring.register(DefaultProxyConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThat(this.service.getClass().getInterfaces()).contains(MethodSecurityService.class); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + } + + @Test + @WithMockUser + public void methodSecurityWhenCustomRunAsManagerThenRunAsWrapsAuthentication() { + this.spring.register(CustomRunAsManagerConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThat(this.service.runAs().getAuthorities()) + .anyMatch(authority -> "ROLE_RUN_AS_SUPER".equals(authority.getAuthority())); + } + + @Test + @WithMockUser + public void methodSecurityWhenSecuredEnabledThenSecures() { + this.spring.register(SecuredConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatThrownBy(() -> this.service.secured()).isInstanceOf(AccessDeniedException.class); + + assertThatCode(() -> this.service.securedUser()).doesNotThrowAnyException(); + + assertThatCode(() -> this.service.preAuthorize()).doesNotThrowAnyException(); + + assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); + } + + @Test + @WithMockUser + public void methodSecurityWhenMissingEnableAnnotationThenShowsHelpfulError() { + assertThatThrownBy(() -> this.spring.register(ExtendsNoEnableAnntotationConfig.class).autowire()) + .hasStackTraceContaining(EnableGlobalMethodSecurity.class.getName() + " is required"); + } + + @Test + @WithMockUser + public void methodSecurityWhenImportingGlobalMethodSecurityConfigurationSubclassThenAuthorizes() { + this.spring.register(ImportSubclassGMSCConfig.class, MethodSecurityServiceConfig.class).autowire(); + + assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); + + assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); + + assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); + } + @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration { @@ -116,16 +306,6 @@ public class NamespaceGlobalMethodSecurityTests { } - // --- after-invocation-provider - - @Test - @WithMockUser - public void methodSecurityWhenCustomAfterInvocationManagerThenAuthorizes() { - this.spring.register(CustomAfterInvocationManagerConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatThrownBy(() -> this.service.preAuthorizePermitAll()).isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration { @@ -157,16 +337,6 @@ public class NamespaceGlobalMethodSecurityTests { } - // --- authentication-manager-ref --- - - @Test - @WithMockUser - public void methodSecurityWhenCustomAuthenticationManagerThenAuthorizes() { - this.spring.register(CustomAuthenticationConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(UnsupportedOperationException.class); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration { @@ -186,44 +356,12 @@ public class NamespaceGlobalMethodSecurityTests { } - // --- jsr250-annotations --- - - @Test - @WithMockUser - public void methodSecurityWhenJsr250EnabledThenAuthorizes() { - this.spring.register(Jsr250Config.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatCode(() -> this.service.preAuthorize()).doesNotThrowAnyException(); - - assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); - - assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(AccessDeniedException.class); - - assertThatCode(() -> this.service.jsr250PermitAll()).doesNotThrowAnyException(); - - } - @EnableGlobalMethodSecurity(jsr250Enabled = true) @Configuration public static class Jsr250Config { } - // --- metadata-source-ref --- - - @Test - @WithMockUser - public void methodSecurityWhenCustomMethodSecurityMetadataSourceThenAuthorizes() { - this.spring.register(CustomMethodSecurityMetadataSourceConfig.class, MethodSecurityServiceConfig.class) - .autowire(); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - - assertThatThrownBy(() -> this.service.secured()).isInstanceOf(AccessDeniedException.class); - - assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration { @@ -247,58 +385,18 @@ public class NamespaceGlobalMethodSecurityTests { } - // --- mode --- - - @Test - @WithMockUser - public void contextRefreshWhenUsingAspectJThenAutowire() throws Exception { - this.spring.register(AspectJModeConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThat(this.spring.getContext().getBean( - Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"))) - .isNotNull(); - assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull(); - - // TODO diagnose why aspectj isn't weaving method security advice around - // MethodSecurityServiceImpl - } - @EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, securedEnabled = true) public static class AspectJModeConfig { } - @Test - public void contextRefreshWhenUsingAspectJAndCustomGlobalMethodSecurityConfigurationThenAutowire() - throws Exception { - - this.spring.register(AspectJModeExtendsGMSCConfig.class).autowire(); - - assertThat(this.spring.getContext().getBean( - Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"))) - .isNotNull(); - assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull(); - - } - @EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, securedEnabled = true) public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration { } - // --- order --- - private static class AdvisorOrderConfig implements ImportBeanDefinitionRegistrar { - private static class ExceptingInterceptor implements MethodInterceptor { - - @Override - public Object invoke(MethodInvocation invocation) { - throw new UnsupportedOperationException("Deny All"); - } - - } - @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { @@ -315,17 +413,15 @@ public class NamespaceGlobalMethodSecurityTests { registry.registerBeanDefinition("exceptingAdvisor", advisor.getBeanDefinition()); } - } + private static class ExceptingInterceptor implements MethodInterceptor { - @Test - @WithMockUser - public void methodSecurityWhenOrderSpecifiedThenConfigured() { - this.spring.register(CustomOrderConfig.class, MethodSecurityServiceConfig.class).autowire(); + @Override + public Object invoke(MethodInvocation invocation) { + throw new UnsupportedOperationException("Deny All"); + } - assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class) - .getOrder()).isEqualTo(-135); + } - assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(AccessDeniedException.class); } @EnableGlobalMethodSecurity(order = -135, jsr250Enabled = true) @@ -334,121 +430,38 @@ public class NamespaceGlobalMethodSecurityTests { } - @Test - @WithMockUser - public void methodSecurityWhenOrderUnspecifiedThenConfiguredToLowestPrecedence() { - this.spring.register(DefaultOrderConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class) - .getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE); - - assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(UnsupportedOperationException.class); - } - @EnableGlobalMethodSecurity(jsr250Enabled = true) @Import(AdvisorOrderConfig.class) public static class DefaultOrderConfig { } - @Test - @WithMockUser - public void methodSecurityWhenOrderUnspecifiedAndCustomGlobalMethodSecurityConfigurationThenConfiguredToLowestPrecedence() { - this.spring.register(DefaultOrderExtendsMethodSecurityConfig.class, MethodSecurityServiceConfig.class) - .autowire(); - - assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class) - .getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE); - - assertThatThrownBy(() -> this.service.jsr250()).isInstanceOf(UnsupportedOperationException.class); - } - @EnableGlobalMethodSecurity(jsr250Enabled = true) @Import(AdvisorOrderConfig.class) public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration { } - // --- pre-post-annotations --- - - @Test - @WithMockUser - public void methodSecurityWhenPrePostEnabledThenPreAuthorizes() { - this.spring.register(PreAuthorizeConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); - - assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) public static class PreAuthorizeConfig { } - @Test - @WithMockUser - public void methodSecurityWhenPrePostEnabledAndCustomGlobalMethodSecurityConfigurationThenPreAuthorizes() { - this.spring.register(PreAuthorizeExtendsGMSCConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); - - assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration { } - // --- proxy-target-class --- - - @Test - @WithMockUser - public void methodSecurityWhenProxyTargetClassThenDoesNotWireToInterface() { - this.spring.register(ProxyTargetClassConfig.class, MethodSecurityServiceConfig.class).autowire(); - - // make sure service was actually proxied - assertThat(this.service.getClass().getInterfaces()).doesNotContain(MethodSecurityService.class); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity(proxyTargetClass = true, prePostEnabled = true) public static class ProxyTargetClassConfig { } - @Test - @WithMockUser - public void methodSecurityWhenDefaultProxyThenWiresToInterface() { - this.spring.register(DefaultProxyConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThat(this.service.getClass().getInterfaces()).contains(MethodSecurityService.class); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) public static class DefaultProxyConfig { } - // --- run-as-manager-ref --- - - @Test - @WithMockUser - public void methodSecurityWhenCustomRunAsManagerThenRunAsWrapsAuthentication() { - this.spring.register(CustomRunAsManagerConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThat(this.service.runAs().getAuthorities()) - .anyMatch(authority -> "ROLE_RUN_AS_SUPER".equals(authority.getAuthority())); - } - @EnableGlobalMethodSecurity(securedEnabled = true) public static class CustomRunAsManagerConfig extends GlobalMethodSecurityConfiguration { @@ -461,53 +474,16 @@ public class NamespaceGlobalMethodSecurityTests { } - // --- secured-annotation --- - - @Test - @WithMockUser - public void methodSecurityWhenSecuredEnabledThenSecures() { - this.spring.register(SecuredConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatThrownBy(() -> this.service.secured()).isInstanceOf(AccessDeniedException.class); - - assertThatCode(() -> this.service.securedUser()).doesNotThrowAnyException(); - - assertThatCode(() -> this.service.preAuthorize()).doesNotThrowAnyException(); - - assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); - } - @EnableGlobalMethodSecurity(securedEnabled = true) public static class SecuredConfig { } - // --- unsorted --- - - @Test - @WithMockUser - public void methodSecurityWhenMissingEnableAnnotationThenShowsHelpfulError() { - assertThatThrownBy(() -> this.spring.register(ExtendsNoEnableAnntotationConfig.class).autowire()) - .hasStackTraceContaining(EnableGlobalMethodSecurity.class.getName() + " is required"); - } - @Configuration public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration { } - @Test - @WithMockUser - public void methodSecurityWhenImportingGlobalMethodSecurityConfigurationSubclassThenAuthorizes() { - this.spring.register(ImportSubclassGMSCConfig.class, MethodSecurityServiceConfig.class).autowire(); - - assertThatCode(() -> this.service.secured()).doesNotThrowAnyException(); - - assertThatCode(() -> this.service.jsr250()).doesNotThrowAnyException(); - - assertThatThrownBy(() -> this.service.preAuthorize()).isInstanceOf(AccessDeniedException.class); - } - @Configuration @Import(PreAuthorizeExtendsGMSCConfig.class) public static class ImportSubclassGMSCConfig { diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java index 575df914fa..13f45b1ca8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java @@ -77,17 +77,6 @@ public class ReactiveMethodSecurityConfigurationTests { assertThat(root.hasRole("ABC")).isTrue(); } - @Configuration - @EnableReactiveMethodSecurity // this imports ReactiveMethodSecurityConfiguration - static class WithRolePrefixConfiguration { - - @Bean - GrantedAuthorityDefaults grantedAuthorityDefaults() { - return new GrantedAuthorityDefaults("CUSTOM_"); - } - - } - @Test public void rolePrefixWithGrantedAuthorityDefaultsAndSubclassWithProxyingEnabled() throws NoSuchMethodException { this.spring.register(SubclassConfig.class).autowire(); @@ -104,6 +93,17 @@ public class ReactiveMethodSecurityConfigurationTests { assertThat(root.hasRole("ABC")).isTrue(); } + @Configuration + @EnableReactiveMethodSecurity // this imports ReactiveMethodSecurityConfiguration + static class WithRolePrefixConfiguration { + + @Bean + GrantedAuthorityDefaults grantedAuthorityDefaults() { + return new GrantedAuthorityDefaults("CUSTOM_"); + } + + } + @Configuration static class SubclassConfig extends ReactiveMethodSecurityConfiguration { diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/SampleEnableGlobalMethodSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/SampleEnableGlobalMethodSecurityTests.java index f2c70cb81e..f16f3586ec 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/SampleEnableGlobalMethodSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/SampleEnableGlobalMethodSecurityTests.java @@ -66,6 +66,16 @@ public class SampleEnableGlobalMethodSecurityTests { assertThatThrownBy(() -> this.methodSecurityService.preAuthorize()).isInstanceOf(AccessDeniedException.class); } + @Test + public void customPermissionHandler() { + this.spring.register(CustomPermissionEvaluatorWebSecurityConfig.class).autowire(); + + assertThat(this.methodSecurityService.hasPermission("allowed")).isNull(); + + assertThatThrownBy(() -> this.methodSecurityService.hasPermission("denied")) + .isInstanceOf(AccessDeniedException.class); + } + @EnableGlobalMethodSecurity(prePostEnabled = true) static class SampleWebSecurityConfig { @@ -86,16 +96,6 @@ public class SampleEnableGlobalMethodSecurityTests { } - @Test - public void customPermissionHandler() { - this.spring.register(CustomPermissionEvaluatorWebSecurityConfig.class).autowire(); - - assertThat(this.methodSecurityService.hasPermission("allowed")).isNull(); - - assertThatThrownBy(() -> this.methodSecurityService.hasPermission("denied")) - .isInstanceOf(AccessDeniedException.class); - } - @EnableGlobalMethodSecurity(prePostEnabled = true) public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration { diff --git a/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java b/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java index 5113be8bf4..c550d4045c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java @@ -88,22 +88,12 @@ public class Sec2758Tests { @EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true) static class SecurityConfig extends WebSecurityConfigurerAdapter { - @RestController - static class RootController { - - @GetMapping("/") - public String ok() { - return "ok"; - } - - } - @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().access("hasAnyRole('CUSTOM')"); + .authorizeRequests() + .anyRequest().access("hasAnyRole('CUSTOM')"); // @formatter:on } @@ -117,6 +107,16 @@ public class Sec2758Tests { return new DefaultRolesPrefixPostProcessor(); } + @RestController + static class RootController { + + @GetMapping("/") + public String ok() { + return "ok"; + } + + } + } static class Service { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java index 3d7dd81d84..06d405188f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java @@ -32,6 +32,39 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon */ public class AbstractRequestMatcherRegistryAnyMatcherTests { + @Test(expected = BeanCreationException.class) + public void antMatchersCanNotWorkAfterAnyRequest() { + loadConfig(AntMatchersAfterAnyRequestConfig.class); + } + + @Test(expected = BeanCreationException.class) + public void mvcMatchersCanNotWorkAfterAnyRequest() { + loadConfig(MvcMatchersAfterAnyRequestConfig.class); + } + + @Test(expected = BeanCreationException.class) + public void regexMatchersCanNotWorkAfterAnyRequest() { + loadConfig(RegexMatchersAfterAnyRequestConfig.class); + } + + @Test(expected = BeanCreationException.class) + public void anyRequestCanNotWorkAfterItself() { + loadConfig(AnyRequestAfterItselfConfig.class); + } + + @Test(expected = BeanCreationException.class) + public void requestMatchersCanNotWorkAfterAnyRequest() { + loadConfig(RequestMatchersAfterAnyRequestConfig.class); + } + + private void loadConfig(Class... configs) { + AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + context.setAllowCircularReferences(false); + context.register(configs); + context.setServletContext(new MockServletContext()); + context.refresh(); + } + @EnableWebSecurity static class AntMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter { @@ -48,11 +81,6 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { } - @Test(expected = BeanCreationException.class) - public void antMatchersCanNotWorkAfterAnyRequest() { - loadConfig(AntMatchersAfterAnyRequestConfig.class); - } - @EnableWebSecurity static class MvcMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter { @@ -69,11 +97,6 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { } - @Test(expected = BeanCreationException.class) - public void mvcMatchersCanNotWorkAfterAnyRequest() { - loadConfig(MvcMatchersAfterAnyRequestConfig.class); - } - @EnableWebSecurity static class RegexMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter { @@ -90,11 +113,6 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { } - @Test(expected = BeanCreationException.class) - public void regexMatchersCanNotWorkAfterAnyRequest() { - loadConfig(RegexMatchersAfterAnyRequestConfig.class); - } - @EnableWebSecurity static class AnyRequestAfterItselfConfig extends WebSecurityConfigurerAdapter { @@ -111,11 +129,6 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { } - @Test(expected = BeanCreationException.class) - public void anyRequestCanNotWorkAfterItself() { - loadConfig(AnyRequestAfterItselfConfig.class); - } - @EnableWebSecurity static class RequestMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter { @@ -132,17 +145,4 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { } - @Test(expected = BeanCreationException.class) - public void requestMatchersCanNotWorkAfterAnyRequest() { - loadConfig(RequestMatchersAfterAnyRequestConfig.class); - } - - private void loadConfig(Class... configs) { - AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); - context.setAllowCircularReferences(false); - context.register(configs); - context.setServletContext(new MockServletContext()); - context.refresh(); - } - } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/SampleWebSecurityConfigurerAdapterTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/SampleWebSecurityConfigurerAdapterTests.java index 978a3e0eed..198c55c3b3 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/SampleWebSecurityConfigurerAdapterTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/SampleWebSecurityConfigurerAdapterTests.java @@ -110,6 +110,106 @@ public class SampleWebSecurityConfigurerAdapterTests { assertThat(this.response.getRedirectedUrl()).isEqualTo("/"); } + @Test + public void readmeSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception { + this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire(); + + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login"); + } + + @Test + public void readmeSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception { + this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire(); + + this.request.setServletPath("/login"); + this.request.setMethod("POST"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error"); + } + + @Test + public void readmeSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception { + this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire(); + + this.request.setServletPath("/login"); + this.request.setMethod("POST"); + this.request.addParameter("username", "user"); + this.request.addParameter("password", "password"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getRedirectedUrl()).isEqualTo("/"); + } + + @Test + public void multiHttpSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception { + this.spring.register(SampleMultiHttpSecurityConfig.class).autowire(); + + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login"); + } + + @Test + public void multiHttpSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception { + this.spring.register(SampleMultiHttpSecurityConfig.class).autowire(); + + this.request.setServletPath("/login"); + this.request.setMethod("POST"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error"); + } + + @Test + public void multiHttpSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception { + this.spring.register(SampleMultiHttpSecurityConfig.class).autowire(); + + this.request.setServletPath("/login"); + this.request.setMethod("POST"); + this.request.addParameter("username", "user"); + this.request.addParameter("password", "password"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getRedirectedUrl()).isEqualTo("/"); + } + + @Test + public void multiHttpSampleWhenRequestProtectedResourceThenStatusUnauthorized() throws Exception { + this.spring.register(SampleMultiHttpSecurityConfig.class).autowire(); + + this.request.setServletPath("/api/admin/test"); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); + } + + @Test + public void multiHttpSampleWhenRequestAdminResourceWithRegularUserThenStatusForbidden() throws Exception { + this.spring.register(SampleMultiHttpSecurityConfig.class).autowire(); + + this.request.setServletPath("/api/admin/test"); + this.request.addHeader("Authorization", + "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes())); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); + } + + @Test + public void multiHttpSampleWhenRequestAdminResourceWithAdminUserThenStatusOk() throws Exception { + this.spring.register(SampleMultiHttpSecurityConfig.class).autowire(); + + this.request.setServletPath("/api/admin/test"); + this.request.addHeader("Authorization", + "Basic " + Base64.getEncoder().encodeToString("admin:password".getBytes())); + this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); + + assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); + } + /** *
 	 *   <http>
@@ -151,39 +251,6 @@ public class SampleWebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void readmeSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception {
-		this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire();
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login");
-	}
-
-	@Test
-	public void readmeSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception {
-		this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire();
-
-		this.request.setServletPath("/login");
-		this.request.setMethod("POST");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error");
-	}
-
-	@Test
-	public void readmeSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception {
-		this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire();
-
-		this.request.setServletPath("/login");
-		this.request.setMethod("POST");
-		this.request.addParameter("username", "user");
-		this.request.addParameter("password", "password");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getRedirectedUrl()).isEqualTo("/");
-	}
-
 	/**
 	 * 
 	 *   <http security="none" pattern="/resources/**"/>
@@ -252,73 +319,6 @@ public class SampleWebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void multiHttpSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception {
-		this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login");
-	}
-
-	@Test
-	public void multiHttpSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception {
-		this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
-
-		this.request.setServletPath("/login");
-		this.request.setMethod("POST");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error");
-	}
-
-	@Test
-	public void multiHttpSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception {
-		this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
-
-		this.request.setServletPath("/login");
-		this.request.setMethod("POST");
-		this.request.addParameter("username", "user");
-		this.request.addParameter("password", "password");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getRedirectedUrl()).isEqualTo("/");
-	}
-
-	@Test
-	public void multiHttpSampleWhenRequestProtectedResourceThenStatusUnauthorized() throws Exception {
-		this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
-
-		this.request.setServletPath("/api/admin/test");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-	}
-
-	@Test
-	public void multiHttpSampleWhenRequestAdminResourceWithRegularUserThenStatusForbidden() throws Exception {
-		this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
-
-		this.request.setServletPath("/api/admin/test");
-		this.request.addHeader("Authorization",
-				"Basic " + Base64.getEncoder().encodeToString("user:password".getBytes()));
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
-	}
-
-	@Test
-	public void multiHttpSampleWhenRequestAdminResourceWithAdminUserThenStatusOk() throws Exception {
-		this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
-
-		this.request.setServletPath("/api/admin/test");
-		this.request.addHeader("Authorization",
-				"Basic " + Base64.getEncoder().encodeToString("admin:password".getBytes()));
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-	}
-
 	/**
 	 * 
 	 *   <http security="none" pattern="/resources/**"/>
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterPowermockTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterPowermockTests.java
index a5cf2d3dd9..7c68fabcde 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterPowermockTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterPowermockTests.java
@@ -90,6 +90,27 @@ public class WebSecurityConfigurerAdapterPowermockTests {
 		assertThat(configurer.configure).isTrue();
 	}
 
+	@Test
+	public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
+		this.spring.register(WebAsyncPopulatedByDefaultConfig.class).autowire();
+
+		WebAsyncManager webAsyncManager = mock(WebAsyncManager.class);
+
+		this.mockMvc.perform(get("/").requestAttr(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE, webAsyncManager));
+
+		ArgumentCaptor callableProcessingInterceptorArgCaptor = ArgumentCaptor
+				.forClass(CallableProcessingInterceptor.class);
+		verify(webAsyncManager, atLeastOnce()).registerCallableInterceptor(any(),
+				callableProcessingInterceptorArgCaptor.capture());
+
+		CallableProcessingInterceptor callableProcessingInterceptor = callableProcessingInterceptorArgCaptor
+				.getAllValues().stream()
+				.filter(e -> SecurityContextCallableProcessingInterceptor.class.isAssignableFrom(e.getClass()))
+				.findFirst().orElse(null);
+
+		assertThat(callableProcessingInterceptor).isNotNull();
+	}
+
 	private void loadConfig(Class... classes) {
 		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
 		context.setClassLoader(getClass().getClassLoader());
@@ -125,27 +146,6 @@ public class WebSecurityConfigurerAdapterPowermockTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
-		this.spring.register(WebAsyncPopulatedByDefaultConfig.class).autowire();
-
-		WebAsyncManager webAsyncManager = mock(WebAsyncManager.class);
-
-		this.mockMvc.perform(get("/").requestAttr(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE, webAsyncManager));
-
-		ArgumentCaptor callableProcessingInterceptorArgCaptor = ArgumentCaptor
-				.forClass(CallableProcessingInterceptor.class);
-		verify(webAsyncManager, atLeastOnce()).registerCallableInterceptor(any(),
-				callableProcessingInterceptorArgCaptor.capture());
-
-		CallableProcessingInterceptor callableProcessingInterceptor = callableProcessingInterceptorArgCaptor
-				.getAllValues().stream()
-				.filter(e -> SecurityContextCallableProcessingInterceptor.class.isAssignableFrom(e.getClass()))
-				.findFirst().orElse(null);
-
-		assertThat(callableProcessingInterceptor).isNotNull();
-	}
-
 	@EnableWebSecurity
 	static class WebAsyncPopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterTests.java
index a31287e6b6..dcd06d382d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/WebSecurityConfigurerAdapterTests.java
@@ -91,6 +91,135 @@ public class WebSecurityConfigurerAdapterTests {
 				.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
 	}
 
+	@Test
+	public void loadConfigWhenRequestAuthenticateThenAuthenticationEventPublished() throws Exception {
+		this.spring.register(InMemoryAuthWithWebSecurityConfigurerAdapter.class).autowire();
+
+		this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
+
+		assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).isNotEmpty();
+		assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).hasSize(1);
+	}
+
+	@Test
+	public void loadConfigWhenInMemoryConfigureProtectedThenPasswordUpgraded() throws Exception {
+		this.spring.register(InMemoryConfigureProtectedConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
+
+		UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
+		assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
+	}
+
+	@Test
+	public void loadConfigWhenInMemoryConfigureGlobalThenPasswordUpgraded() throws Exception {
+		this.spring.register(InMemoryConfigureGlobalConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
+
+		UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
+		assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
+	}
+
+	@Test
+	public void loadConfigWhenCustomContentNegotiationStrategyBeanThenOverridesDefault() {
+		OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN = mock(
+				ContentNegotiationStrategy.class);
+		this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class).autowire();
+
+		OverrideContentNegotiationStrategySharedObjectConfig securityConfig = this.spring.getContext()
+				.getBean(OverrideContentNegotiationStrategySharedObjectConfig.class);
+
+		assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
+		assertThat(securityConfig.contentNegotiationStrategySharedObject)
+				.isSameAs(OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN);
+	}
+
+	@Test
+	public void loadConfigWhenDefaultContentNegotiationStrategyThenHeaderContentNegotiationStrategy() {
+		this.spring.register(ContentNegotiationStrategyDefaultSharedObjectConfig.class).autowire();
+
+		ContentNegotiationStrategyDefaultSharedObjectConfig securityConfig = this.spring.getContext()
+				.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig.class);
+
+		assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
+		assertThat(securityConfig.contentNegotiationStrategySharedObject)
+				.isInstanceOf(HeaderContentNegotiationStrategy.class);
+	}
+
+	@Test
+	public void loadConfigWhenUserDetailsServiceHasCircularReferenceThenStillLoads() {
+		this.spring.register(RequiresUserDetailsServiceConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		MyFilter myFilter = this.spring.getContext().getBean(MyFilter.class);
+
+		Throwable thrown = catchThrowable(() -> myFilter.userDetailsService.loadUserByUsername("user"));
+		assertThat(thrown).isNull();
+
+		thrown = catchThrowable(() -> myFilter.userDetailsService.loadUserByUsername("admin"));
+		assertThat(thrown).isInstanceOf(UsernameNotFoundException.class);
+	}
+
+	// SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object
+	@Test
+	public void loadConfigWhenSharedObjectsCreatedThenApplicationContextAdded() {
+		this.spring.register(ApplicationContextSharedObjectConfig.class).autowire();
+
+		ApplicationContextSharedObjectConfig securityConfig = this.spring.getContext()
+				.getBean(ApplicationContextSharedObjectConfig.class);
+
+		assertThat(securityConfig.applicationContextSharedObject).isNotNull();
+		assertThat(securityConfig.applicationContextSharedObject).isSameAs(this.spring.getContext());
+	}
+
+	@Test
+	public void loadConfigWhenCustomAuthenticationTrustResolverBeanThenOverridesDefault() {
+		CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN = mock(AuthenticationTrustResolver.class);
+		this.spring.register(CustomTrustResolverConfig.class).autowire();
+
+		CustomTrustResolverConfig securityConfig = this.spring.getContext().getBean(CustomTrustResolverConfig.class);
+
+		assertThat(securityConfig.authenticationTrustResolverSharedObject).isNotNull();
+		assertThat(securityConfig.authenticationTrustResolverSharedObject)
+				.isSameAs(CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN);
+	}
+
+	@Test
+	public void compareOrderWebSecurityConfigurerAdapterWhenLowestOrderToDefaultOrderThenGreaterThanZero() {
+		AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
+		assertThat(comparator.compare(new LowestPriorityWebSecurityConfig(), new DefaultOrderWebSecurityConfig()))
+				.isGreaterThan(0);
+	}
+
+	// gh-7515
+	@Test
+	public void performWhenUsingAuthenticationEventPublisherBeanThenUses() throws Exception {
+		this.spring.register(CustomAuthenticationEventPublisherBean.class).autowire();
+
+		AuthenticationEventPublisher authenticationEventPublisher = this.spring.getContext()
+				.getBean(AuthenticationEventPublisher.class);
+
+		this.mockMvc.perform(get("/").with(httpBasic("user", "password")));
+
+		verify(authenticationEventPublisher).publishAuthenticationSuccess(any(Authentication.class));
+	}
+
+	// gh-4400
+	@Test
+	public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception {
+		this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire();
+
+		AuthenticationEventPublisher authenticationEventPublisher = CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER;
+
+		this.mockMvc.perform(get("/").with(httpBasic("user", "password"))); // fails since
+																			// no
+																			// providers
+																			// configured
+
+		verify(authenticationEventPublisher).publishAuthenticationFailure(any(AuthenticationException.class),
+				any(Authentication.class));
+	}
+
 	@EnableWebSecurity
 	static class HeadersArePopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
 
@@ -109,16 +238,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenRequestAuthenticateThenAuthenticationEventPublished() throws Exception {
-		this.spring.register(InMemoryAuthWithWebSecurityConfigurerAdapter.class).autowire();
-
-		this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
-
-		assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).isNotEmpty();
-		assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).hasSize(1);
-	}
-
 	@EnableWebSecurity
 	static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter
 			implements ApplicationListener {
@@ -141,16 +260,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenInMemoryConfigureProtectedThenPasswordUpgraded() throws Exception {
-		this.spring.register(InMemoryConfigureProtectedConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
-
-		UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
-		assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
-	}
-
 	@EnableWebSecurity
 	static class InMemoryConfigureProtectedConfig extends WebSecurityConfigurerAdapter {
 
@@ -171,16 +280,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenInMemoryConfigureGlobalThenPasswordUpgraded() throws Exception {
-		this.spring.register(InMemoryConfigureGlobalConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
-
-		UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
-		assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
-	}
-
 	@EnableWebSecurity
 	static class InMemoryConfigureGlobalConfig extends WebSecurityConfigurerAdapter {
 
@@ -201,20 +300,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenCustomContentNegotiationStrategyBeanThenOverridesDefault() {
-		OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN = mock(
-				ContentNegotiationStrategy.class);
-		this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class).autowire();
-
-		OverrideContentNegotiationStrategySharedObjectConfig securityConfig = this.spring.getContext()
-				.getBean(OverrideContentNegotiationStrategySharedObjectConfig.class);
-
-		assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
-		assertThat(securityConfig.contentNegotiationStrategySharedObject)
-				.isSameAs(OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN);
-	}
-
 	@EnableWebSecurity
 	static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
 
@@ -235,18 +320,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenDefaultContentNegotiationStrategyThenHeaderContentNegotiationStrategy() {
-		this.spring.register(ContentNegotiationStrategyDefaultSharedObjectConfig.class).autowire();
-
-		ContentNegotiationStrategyDefaultSharedObjectConfig securityConfig = this.spring.getContext()
-				.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig.class);
-
-		assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
-		assertThat(securityConfig.contentNegotiationStrategySharedObject)
-				.isInstanceOf(HeaderContentNegotiationStrategy.class);
-	}
-
 	@EnableWebSecurity
 	static class ContentNegotiationStrategyDefaultSharedObjectConfig extends WebSecurityConfigurerAdapter {
 
@@ -260,19 +333,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenUserDetailsServiceHasCircularReferenceThenStillLoads() {
-		this.spring.register(RequiresUserDetailsServiceConfig.class, UserDetailsServiceConfig.class).autowire();
-
-		MyFilter myFilter = this.spring.getContext().getBean(MyFilter.class);
-
-		Throwable thrown = catchThrowable(() -> myFilter.userDetailsService.loadUserByUsername("user"));
-		assertThat(thrown).isNull();
-
-		thrown = catchThrowable(() -> myFilter.userDetailsService.loadUserByUsername("admin"));
-		assertThat(thrown).isInstanceOf(UsernameNotFoundException.class);
-	}
-
 	@Configuration
 	static class RequiresUserDetailsServiceConfig {
 
@@ -327,18 +387,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	// SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object
-	@Test
-	public void loadConfigWhenSharedObjectsCreatedThenApplicationContextAdded() {
-		this.spring.register(ApplicationContextSharedObjectConfig.class).autowire();
-
-		ApplicationContextSharedObjectConfig securityConfig = this.spring.getContext()
-				.getBean(ApplicationContextSharedObjectConfig.class);
-
-		assertThat(securityConfig.applicationContextSharedObject).isNotNull();
-		assertThat(securityConfig.applicationContextSharedObject).isSameAs(this.spring.getContext());
-	}
-
 	@EnableWebSecurity
 	static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
 
@@ -352,18 +400,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenCustomAuthenticationTrustResolverBeanThenOverridesDefault() {
-		CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN = mock(AuthenticationTrustResolver.class);
-		this.spring.register(CustomTrustResolverConfig.class).autowire();
-
-		CustomTrustResolverConfig securityConfig = this.spring.getContext().getBean(CustomTrustResolverConfig.class);
-
-		assertThat(securityConfig.authenticationTrustResolverSharedObject).isNotNull();
-		assertThat(securityConfig.authenticationTrustResolverSharedObject)
-				.isSameAs(CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN);
-	}
-
 	@EnableWebSecurity
 	static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
 
@@ -384,13 +420,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	@Test
-	public void compareOrderWebSecurityConfigurerAdapterWhenLowestOrderToDefaultOrderThenGreaterThanZero() {
-		AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
-		assertThat(comparator.compare(new LowestPriorityWebSecurityConfig(), new DefaultOrderWebSecurityConfig()))
-				.isGreaterThan(0);
-	}
-
 	static class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {
 
 	}
@@ -400,19 +429,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	// gh-7515
-	@Test
-	public void performWhenUsingAuthenticationEventPublisherBeanThenUses() throws Exception {
-		this.spring.register(CustomAuthenticationEventPublisherBean.class).autowire();
-
-		AuthenticationEventPublisher authenticationEventPublisher = this.spring.getContext()
-				.getBean(AuthenticationEventPublisher.class);
-
-		this.mockMvc.perform(get("/").with(httpBasic("user", "password")));
-
-		verify(authenticationEventPublisher).publishAuthenticationSuccess(any(Authentication.class));
-	}
-
 	@EnableWebSecurity
 	static class CustomAuthenticationEventPublisherBean extends WebSecurityConfigurerAdapter {
 
@@ -429,22 +445,6 @@ public class WebSecurityConfigurerAdapterTests {
 
 	}
 
-	// gh-4400
-	@Test
-	public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception {
-		this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire();
-
-		AuthenticationEventPublisher authenticationEventPublisher = CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER;
-
-		this.mockMvc.perform(get("/").with(httpBasic("user", "password"))); // fails since
-																			// no
-																			// providers
-																			// configured
-
-		verify(authenticationEventPublisher).publishAuthenticationFailure(any(AuthenticationException.class),
-				any(Authentication.class));
-	}
-
 	@EnableWebSecurity
 	static class CustomAuthenticationEventPublisherDsl extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java
index 79e610a314..e84265cfdf 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java
@@ -69,6 +69,28 @@ public class HttpConfigurationTests {
 				+ " Consider using addFilterBefore or addFilterAfter instead.");
 	}
 
+	// https://github.com/spring-projects/spring-security-javaconfig/issues/104
+	@Test
+	public void configureWhenAddFilterCasAuthenticationFilterThenFilterAdded() throws Exception {
+		CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER = spy(new CasAuthenticationFilter());
+		this.spring.register(CasAuthenticationFilterConfig.class).autowire();
+
+		this.mockMvc.perform(get("/"));
+
+		verify(CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER).doFilter(any(ServletRequest.class),
+				any(ServletResponse.class), any(FilterChain.class));
+	}
+
+	@Test
+	public void configureWhenConfigIsRequestMatchersJavadocThenAuthorizationApplied() throws Exception {
+		this.spring.register(RequestMatcherRegistryConfigs.class).autowire();
+
+		this.mockMvc.perform(get("/oauth/a")).andExpect(status().isUnauthorized());
+		this.mockMvc.perform(get("/oauth/b")).andExpect(status().isUnauthorized());
+		this.mockMvc.perform(get("/api/a")).andExpect(status().isUnauthorized());
+		this.mockMvc.perform(get("/api/b")).andExpect(status().isUnauthorized());
+	}
+
 	@EnableWebSecurity
 	static class UnregisteredFilterConfig extends WebSecurityConfigurerAdapter {
 
@@ -101,18 +123,6 @@ public class HttpConfigurationTests {
 
 	}
 
-	// https://github.com/spring-projects/spring-security-javaconfig/issues/104
-	@Test
-	public void configureWhenAddFilterCasAuthenticationFilterThenFilterAdded() throws Exception {
-		CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER = spy(new CasAuthenticationFilter());
-		this.spring.register(CasAuthenticationFilterConfig.class).autowire();
-
-		this.mockMvc.perform(get("/"));
-
-		verify(CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER).doFilter(any(ServletRequest.class),
-				any(ServletResponse.class), any(FilterChain.class));
-	}
-
 	@EnableWebSecurity
 	static class CasAuthenticationFilterConfig extends WebSecurityConfigurerAdapter {
 
@@ -128,16 +138,6 @@ public class HttpConfigurationTests {
 
 	}
 
-	@Test
-	public void configureWhenConfigIsRequestMatchersJavadocThenAuthorizationApplied() throws Exception {
-		this.spring.register(RequestMatcherRegistryConfigs.class).autowire();
-
-		this.mockMvc.perform(get("/oauth/a")).andExpect(status().isUnauthorized());
-		this.mockMvc.perform(get("/oauth/b")).andExpect(status().isUnauthorized());
-		this.mockMvc.perform(get("/api/a")).andExpect(status().isUnauthorized());
-		this.mockMvc.perform(get("/api/b")).andExpect(status().isUnauthorized());
-	}
-
 	@EnableWebSecurity
 	static class RequestMatcherRegistryConfigs extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java
index d695d5624d..4744963b5c 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java
@@ -101,6 +101,212 @@ public class NamespaceHttpTests {
 				any(), anyCollection());
 	}
 
+	@Test // http@access-denied-page
+	public void configureWhenAccessDeniedPageSetAndRequestForbiddenThenForwardedToAccessDeniedPage() throws Exception {
+		this.spring.register(AccessDeniedPageConfig.class).autowire();
+
+		this.mockMvc.perform(get("/admin").with(user(PasswordEncodedUser.user()))).andExpect(status().isForbidden())
+				.andExpect(forwardedUrl("/AccessDeniedPage"));
+	}
+
+	@Test // http@authentication-manager-ref
+	public void configureWhenAuthenticationManagerProvidedThenVerifyUse() throws Exception {
+		AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
+		this.spring.register(AuthenticationManagerRefConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin());
+
+		verify(AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER, times(1)).authenticate(any(Authentication.class));
+	}
+
+	@Test // http@create-session=always
+	public void configureWhenSessionCreationPolicyAlwaysThenSessionCreatedOnRequest() throws Exception {
+		this.spring.register(CreateSessionAlwaysConfig.class).autowire();
+
+		MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+
+		assertThat(session).isNotNull();
+		assertThat(session.isNew()).isTrue();
+	}
+
+	@Test // http@create-session=stateless
+	public void configureWhenSessionCreationPolicyStatelessThenSessionNotCreatedOnRequest() throws Exception {
+		this.spring.register(CreateSessionStatelessConfig.class).autowire();
+
+		MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+
+		assertThat(session).isNull();
+	}
+
+	@Test // http@create-session=ifRequired
+	public void configureWhenSessionCreationPolicyIfRequiredThenSessionCreatedWhenRequiredOnRequest() throws Exception {
+		this.spring.register(IfRequiredConfig.class).autowire();
+
+		MvcResult mvcResult = this.mockMvc.perform(get("/unsecure")).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+
+		assertThat(session).isNull();
+
+		mvcResult = this.mockMvc.perform(formLogin()).andReturn();
+		session = mvcResult.getRequest().getSession(false);
+
+		assertThat(session).isNotNull();
+		assertThat(session.isNew()).isTrue();
+	}
+
+	@Test // http@create-session=never
+	public void configureWhenSessionCreationPolicyNeverThenSessionNotCreatedOnRequest() throws Exception {
+		this.spring.register(CreateSessionNeverConfig.class).autowire();
+
+		MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+
+		assertThat(session).isNull();
+	}
+
+	@Test // http@entry-point-ref
+	public void configureWhenAuthenticationEntryPointSetAndRequestUnauthorizedThenRedirectedToAuthenticationEntryPoint()
+			throws Exception {
+		this.spring.register(EntryPointRefConfig.class).autowire();
+
+		this.mockMvc.perform(get("/")).andExpect(status().is3xxRedirection())
+				.andExpect(redirectedUrlPattern("**/entry-point"));
+	}
+
+	@Test // http@jaas-api-provision
+	public void configureWhenJaasApiIntegrationFilterAddedThenJaasSubjectObtained() throws Exception {
+		LoginContext loginContext = mock(LoginContext.class);
+		when(loginContext.getSubject()).thenReturn(new Subject());
+
+		JaasAuthenticationToken authenticationToken = mock(JaasAuthenticationToken.class);
+		when(authenticationToken.isAuthenticated()).thenReturn(true);
+		when(authenticationToken.getLoginContext()).thenReturn(loginContext);
+
+		this.spring.register(JaasApiProvisionConfig.class).autowire();
+
+		this.mockMvc.perform(get("/").with(authentication(authenticationToken)));
+
+		verify(loginContext, times(1)).getSubject();
+	}
+
+	@Test // http@realm
+	public void configureWhenHttpBasicAndRequestUnauthorizedThenReturnWWWAuthenticateWithRealm() throws Exception {
+		this.spring.register(RealmConfig.class).autowire();
+
+		this.mockMvc.perform(get("/")).andExpect(status().isUnauthorized())
+				.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
+	}
+
+	@Test // http@request-matcher-ref ant
+	public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() {
+		this.spring.register(RequestMatcherAntConfig.class).autowire();
+
+		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
+
+		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
+		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
+				.get(0);
+		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
+	}
+
+	@Test // http@request-matcher-ref regex
+	public void configureWhenRegexPatternMatchingThenRegexRequestMatcherUsed() {
+		this.spring.register(RequestMatcherRegexConfig.class).autowire();
+
+		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
+
+		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
+		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
+				.get(0);
+		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(RegexRequestMatcher.class);
+	}
+
+	@Test // http@request-matcher-ref
+	public void configureWhenRequestMatcherProvidedThenRequestMatcherUsed() {
+		this.spring.register(RequestMatcherRefConfig.class).autowire();
+
+		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
+
+		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
+		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
+				.get(0);
+		assertThat(securityFilterChain.getRequestMatcher())
+				.isInstanceOf(RequestMatcherRefConfig.MyRequestMatcher.class);
+	}
+
+	@Test // http@security=none
+	public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() {
+		this.spring.register(SecurityNoneConfig.class).autowire();
+
+		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
+
+		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
+		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
+				.get(0);
+		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
+		assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
+				.isEqualTo("/resources/**");
+		assertThat(securityFilterChain.getFilters()).isEmpty();
+
+		assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class);
+		securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1);
+		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
+		assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
+				.isEqualTo("/public/**");
+		assertThat(securityFilterChain.getFilters()).isEmpty();
+	}
+
+	@Test // http@security-context-repository-ref
+	public void configureWhenNullSecurityContextRepositoryThenSecurityContextNotSavedInSession() throws Exception {
+		this.spring.register(SecurityContextRepoConfig.class).autowire();
+
+		MvcResult mvcResult = this.mockMvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNull();
+	}
+
+	@Test // http@servlet-api-provision=false
+	public void configureWhenServletApiDisabledThenRequestNotServletApiWrapper() throws Exception {
+		this.spring.register(ServletApiProvisionConfig.class, MainController.class).autowire();
+
+		this.mockMvc.perform(get("/"));
+
+		assertThat(MainController.HTTP_SERVLET_REQUEST_TYPE)
+				.isNotInstanceOf(SecurityContextHolderAwareRequestWrapper.class);
+	}
+
+	@Test // http@servlet-api-provision defaults to true
+	public void configureWhenServletApiDefaultThenRequestIsServletApiWrapper() throws Exception {
+		this.spring.register(ServletApiProvisionDefaultsConfig.class, MainController.class).autowire();
+
+		this.mockMvc.perform(get("/"));
+
+		assertThat(SecurityContextHolderAwareRequestWrapper.class)
+				.isAssignableFrom(MainController.HTTP_SERVLET_REQUEST_TYPE);
+	}
+
+	@Test // http@use-expressions=true
+	public void configureWhenUseExpressionsEnabledThenExpressionBasedSecurityMetadataSource() {
+		this.spring.register(UseExpressionsConfig.class).autowire();
+
+		UseExpressionsConfig config = this.spring.getContext().getBean(UseExpressionsConfig.class);
+
+		assertThat(ExpressionBasedFilterInvocationSecurityMetadataSource.class)
+				.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
+	}
+
+	@Test // http@use-expressions=false
+	public void configureWhenUseExpressionsDisabledThenDefaultSecurityMetadataSource() {
+		this.spring.register(DisableUseExpressionsConfig.class).autowire();
+
+		DisableUseExpressionsConfig config = this.spring.getContext().getBean(DisableUseExpressionsConfig.class);
+
+		assertThat(DefaultFilterInvocationSecurityMetadataSource.class)
+				.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
+	}
+
 	@EnableWebSecurity
 	static class AccessDecisionManagerRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -118,14 +324,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@access-denied-page
-	public void configureWhenAccessDeniedPageSetAndRequestForbiddenThenForwardedToAccessDeniedPage() throws Exception {
-		this.spring.register(AccessDeniedPageConfig.class).autowire();
-
-		this.mockMvc.perform(get("/admin").with(user(PasswordEncodedUser.user()))).andExpect(status().isForbidden())
-				.andExpect(forwardedUrl("/AccessDeniedPage"));
-	}
-
 	@EnableWebSecurity
 	static class AccessDeniedPageConfig extends WebSecurityConfigurerAdapter {
 
@@ -144,16 +342,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@authentication-manager-ref
-	public void configureWhenAuthenticationManagerProvidedThenVerifyUse() throws Exception {
-		AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
-		this.spring.register(AuthenticationManagerRefConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin());
-
-		verify(AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER, times(1)).authenticate(any(Authentication.class));
-	}
-
 	@EnableWebSecurity
 	static class AuthenticationManagerRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -177,17 +365,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@create-session=always
-	public void configureWhenSessionCreationPolicyAlwaysThenSessionCreatedOnRequest() throws Exception {
-		this.spring.register(CreateSessionAlwaysConfig.class).autowire();
-
-		MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-
-		assertThat(session).isNotNull();
-		assertThat(session.isNew()).isTrue();
-	}
-
 	@EnableWebSecurity
 	static class CreateSessionAlwaysConfig extends WebSecurityConfigurerAdapter {
 
@@ -205,16 +382,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@create-session=stateless
-	public void configureWhenSessionCreationPolicyStatelessThenSessionNotCreatedOnRequest() throws Exception {
-		this.spring.register(CreateSessionStatelessConfig.class).autowire();
-
-		MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-
-		assertThat(session).isNull();
-	}
-
 	@EnableWebSecurity
 	static class CreateSessionStatelessConfig extends WebSecurityConfigurerAdapter {
 
@@ -232,22 +399,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@create-session=ifRequired
-	public void configureWhenSessionCreationPolicyIfRequiredThenSessionCreatedWhenRequiredOnRequest() throws Exception {
-		this.spring.register(IfRequiredConfig.class).autowire();
-
-		MvcResult mvcResult = this.mockMvc.perform(get("/unsecure")).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-
-		assertThat(session).isNull();
-
-		mvcResult = this.mockMvc.perform(formLogin()).andReturn();
-		session = mvcResult.getRequest().getSession(false);
-
-		assertThat(session).isNotNull();
-		assertThat(session.isNew()).isTrue();
-	}
-
 	@EnableWebSecurity
 	static class IfRequiredConfig extends WebSecurityConfigurerAdapter {
 
@@ -268,16 +419,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@create-session=never
-	public void configureWhenSessionCreationPolicyNeverThenSessionNotCreatedOnRequest() throws Exception {
-		this.spring.register(CreateSessionNeverConfig.class).autowire();
-
-		MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-
-		assertThat(session).isNull();
-	}
-
 	@EnableWebSecurity
 	static class CreateSessionNeverConfig extends WebSecurityConfigurerAdapter {
 
@@ -295,15 +436,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@entry-point-ref
-	public void configureWhenAuthenticationEntryPointSetAndRequestUnauthorizedThenRedirectedToAuthenticationEntryPoint()
-			throws Exception {
-		this.spring.register(EntryPointRefConfig.class).autowire();
-
-		this.mockMvc.perform(get("/")).andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrlPattern("**/entry-point"));
-	}
-
 	@EnableWebSecurity
 	static class EntryPointRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -323,22 +455,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@jaas-api-provision
-	public void configureWhenJaasApiIntegrationFilterAddedThenJaasSubjectObtained() throws Exception {
-		LoginContext loginContext = mock(LoginContext.class);
-		when(loginContext.getSubject()).thenReturn(new Subject());
-
-		JaasAuthenticationToken authenticationToken = mock(JaasAuthenticationToken.class);
-		when(authenticationToken.isAuthenticated()).thenReturn(true);
-		when(authenticationToken.getLoginContext()).thenReturn(loginContext);
-
-		this.spring.register(JaasApiProvisionConfig.class).autowire();
-
-		this.mockMvc.perform(get("/").with(authentication(authenticationToken)));
-
-		verify(loginContext, times(1)).getSubject();
-	}
-
 	@EnableWebSecurity
 	static class JaasApiProvisionConfig extends WebSecurityConfigurerAdapter {
 
@@ -352,14 +468,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@realm
-	public void configureWhenHttpBasicAndRequestUnauthorizedThenReturnWWWAuthenticateWithRealm() throws Exception {
-		this.spring.register(RealmConfig.class).autowire();
-
-		this.mockMvc.perform(get("/")).andExpect(status().isUnauthorized())
-				.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
-	}
-
 	@EnableWebSecurity
 	static class RealmConfig extends WebSecurityConfigurerAdapter {
 
@@ -377,18 +485,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@request-matcher-ref ant
-	public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() {
-		this.spring.register(RequestMatcherAntConfig.class).autowire();
-
-		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
-
-		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
-		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
-				.get(0);
-		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
-	}
-
 	@EnableWebSecurity
 	static class RequestMatcherAntConfig extends WebSecurityConfigurerAdapter {
 
@@ -402,18 +498,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@request-matcher-ref regex
-	public void configureWhenRegexPatternMatchingThenRegexRequestMatcherUsed() {
-		this.spring.register(RequestMatcherRegexConfig.class).autowire();
-
-		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
-
-		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
-		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
-				.get(0);
-		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(RegexRequestMatcher.class);
-	}
-
 	@EnableWebSecurity
 	static class RequestMatcherRegexConfig extends WebSecurityConfigurerAdapter {
 
@@ -427,19 +511,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@request-matcher-ref
-	public void configureWhenRequestMatcherProvidedThenRequestMatcherUsed() {
-		this.spring.register(RequestMatcherRefConfig.class).autowire();
-
-		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
-
-		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
-		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
-				.get(0);
-		assertThat(securityFilterChain.getRequestMatcher())
-				.isInstanceOf(RequestMatcherRefConfig.MyRequestMatcher.class);
-	}
-
 	@EnableWebSecurity
 	static class RequestMatcherRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -462,28 +533,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@security=none
-	public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() {
-		this.spring.register(SecurityNoneConfig.class).autowire();
-
-		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
-
-		assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
-		DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
-				.get(0);
-		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
-		assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
-				.isEqualTo("/resources/**");
-		assertThat(securityFilterChain.getFilters()).isEmpty();
-
-		assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class);
-		securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1);
-		assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
-		assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
-				.isEqualTo("/public/**");
-		assertThat(securityFilterChain.getFilters()).isEmpty();
-	}
-
 	@EnableWebSecurity
 	static class SecurityNoneConfig extends WebSecurityConfigurerAdapter {
 
@@ -498,15 +547,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@security-context-repository-ref
-	public void configureWhenNullSecurityContextRepositoryThenSecurityContextNotSavedInSession() throws Exception {
-		this.spring.register(SecurityContextRepoConfig.class).autowire();
-
-		MvcResult mvcResult = this.mockMvc.perform(formLogin()).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-		assertThat(session).isNull();
-	}
-
 	@EnableWebSecurity
 	static class SecurityContextRepoConfig extends WebSecurityConfigurerAdapter {
 
@@ -535,16 +575,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@servlet-api-provision=false
-	public void configureWhenServletApiDisabledThenRequestNotServletApiWrapper() throws Exception {
-		this.spring.register(ServletApiProvisionConfig.class, MainController.class).autowire();
-
-		this.mockMvc.perform(get("/"));
-
-		assertThat(MainController.HTTP_SERVLET_REQUEST_TYPE)
-				.isNotInstanceOf(SecurityContextHolderAwareRequestWrapper.class);
-	}
-
 	@EnableWebSecurity
 	static class ServletApiProvisionConfig extends WebSecurityConfigurerAdapter {
 
@@ -562,16 +592,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@servlet-api-provision defaults to true
-	public void configureWhenServletApiDefaultThenRequestIsServletApiWrapper() throws Exception {
-		this.spring.register(ServletApiProvisionDefaultsConfig.class, MainController.class).autowire();
-
-		this.mockMvc.perform(get("/"));
-
-		assertThat(SecurityContextHolderAwareRequestWrapper.class)
-				.isAssignableFrom(MainController.HTTP_SERVLET_REQUEST_TYPE);
-	}
-
 	@EnableWebSecurity
 	static class ServletApiProvisionDefaultsConfig extends WebSecurityConfigurerAdapter {
 
@@ -599,16 +619,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@use-expressions=true
-	public void configureWhenUseExpressionsEnabledThenExpressionBasedSecurityMetadataSource() {
-		this.spring.register(UseExpressionsConfig.class).autowire();
-
-		UseExpressionsConfig config = this.spring.getContext().getBean(UseExpressionsConfig.class);
-
-		assertThat(ExpressionBasedFilterInvocationSecurityMetadataSource.class)
-				.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
-	}
-
 	@EnableWebSecurity
 	static class UseExpressionsConfig extends WebSecurityConfigurerAdapter {
 
@@ -638,16 +648,6 @@ public class NamespaceHttpTests {
 
 	}
 
-	@Test // http@use-expressions=false
-	public void configureWhenUseExpressionsDisabledThenDefaultSecurityMetadataSource() {
-		this.spring.register(DisableUseExpressionsConfig.class).autowire();
-
-		DisableUseExpressionsConfig config = this.spring.getContext().getBean(DisableUseExpressionsConfig.class);
-
-		assertThat(DefaultFilterInvocationSecurityMetadataSource.class)
-				.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
-	}
-
 	@EnableWebSecurity
 	static class DisableUseExpressionsConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java
index b773e244c8..223dabf3b2 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java
@@ -103,6 +103,50 @@ public class WebSecurityTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
 	}
 
+	@Test
+	public void ignoringMvcMatcherServletPath() throws Exception {
+		loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		setup();
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path.html");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		setup();
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path/");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		setup();
+
+		this.request.setServletPath("/other");
+		this.request.setRequestURI("/other/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+	}
+
+	public void loadConfig(Class... configs) {
+		this.context = new AnnotationConfigWebApplicationContext();
+		this.context.register(configs);
+		this.context.setServletContext(new MockServletContext());
+		this.context.refresh();
+
+		this.context.getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -147,41 +191,6 @@ public class WebSecurityTests {
 
 	}
 
-	@Test
-	public void ignoringMvcMatcherServletPath() throws Exception {
-		loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		setup();
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path.html");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		setup();
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path/");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		setup();
-
-		this.request.setServletPath("/other");
-		this.request.setRequestURI("/other/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -237,13 +246,4 @@ public class WebSecurityTests {
 
 	}
 
-	public void loadConfig(Class... configs) {
-		this.context = new AnnotationConfigWebApplicationContext();
-		this.context.register(configs);
-		this.context.setServletContext(new MockServletContext());
-		this.context.refresh();
-
-		this.context.getAutowireCapableBeanFactory().autowireBean(this);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java
index aaa399372f..962db3234d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java
@@ -63,6 +63,48 @@ public class EnableWebSecurityTests {
 		assertThat(authentication.isAuthenticated()).isTrue();
 	}
 
+	@Test
+	public void loadConfigWhenChildConfigExtendsSecurityConfigThenSecurityConfigInherited() {
+		this.spring.register(ChildSecurityConfig.class).autowire();
+		this.spring.getContext().getBean("springSecurityFilterChain", DebugFilter.class);
+	}
+
+	@Test
+	public void configureWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
+		this.spring.register(AuthenticationPrincipalConfig.class).autowire();
+
+		this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
+				.andExpect(content().string("user1"));
+	}
+
+	@Test
+	public void securityFilterChainWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
+		this.spring.register(SecurityFilterChainAuthenticationPrincipalConfig.class).autowire();
+
+		this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
+				.andExpect(content().string("user1"));
+	}
+
+	@Test
+	public void enableWebSecurityWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
+		this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
+
+		Child childBean = this.spring.getContext().getBean(Child.class);
+		Parent parentBean = this.spring.getContext().getBean(Parent.class);
+
+		assertThat(parentBean.getChild()).isSameAs(childBean);
+	}
+
+	@Test
+	public void enableWebSecurityWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
+		this.spring.register(BeanProxyDisabledConfig.class).autowire();
+
+		Child childBean = this.spring.getContext().getBean(Child.class);
+		Parent parentBean = this.spring.getContext().getBean(Parent.class);
+
+		assertThat(parentBean.getChild()).isNotSameAs(childBean);
+	}
+
 	@EnableWebSecurity
 	static class SecurityConfig extends WebSecurityConfigurerAdapter {
 
@@ -94,12 +136,6 @@ public class EnableWebSecurityTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenChildConfigExtendsSecurityConfigThenSecurityConfigInherited() {
-		this.spring.register(ChildSecurityConfig.class).autowire();
-		this.spring.getContext().getBean("springSecurityFilterChain", DebugFilter.class);
-	}
-
 	@Configuration
 	static class ChildSecurityConfig extends DebugSecurityConfig {
 
@@ -110,14 +146,6 @@ public class EnableWebSecurityTests {
 
 	}
 
-	@Test
-	public void configureWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
-		this.spring.register(AuthenticationPrincipalConfig.class).autowire();
-
-		this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
-				.andExpect(content().string("user1"));
-	}
-
 	@EnableWebSecurity
 	@EnableWebMvc
 	static class AuthenticationPrincipalConfig extends WebSecurityConfigurerAdapter {
@@ -138,14 +166,6 @@ public class EnableWebSecurityTests {
 
 	}
 
-	@Test
-	public void securityFilterChainWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
-		this.spring.register(SecurityFilterChainAuthenticationPrincipalConfig.class).autowire();
-
-		this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
-				.andExpect(content().string("user1"));
-	}
-
 	@EnableWebSecurity
 	@EnableWebMvc
 	static class SecurityFilterChainAuthenticationPrincipalConfig {
@@ -167,16 +187,6 @@ public class EnableWebSecurityTests {
 
 	}
 
-	@Test
-	public void enableWebSecurityWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
-		this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
-
-		Child childBean = this.spring.getContext().getBean(Child.class);
-		Parent parentBean = this.spring.getContext().getBean(Parent.class);
-
-		assertThat(parentBean.getChild()).isSameAs(childBean);
-	}
-
 	@EnableWebSecurity
 	static class BeanProxyEnabledByDefaultConfig extends WebSecurityConfigurerAdapter {
 
@@ -192,16 +202,6 @@ public class EnableWebSecurityTests {
 
 	}
 
-	@Test
-	public void enableWebSecurityWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
-		this.spring.register(BeanProxyDisabledConfig.class).autowire();
-
-		Child childBean = this.spring.getContext().getBean(Child.class);
-		Parent parentBean = this.spring.getContext().getBean(Parent.class);
-
-		assertThat(parentBean.getChild()).isNotSameAs(childBean);
-	}
-
 	@Configuration(proxyBeanMethods = false)
 	@EnableWebSecurity
 	static class BeanProxyDisabledConfig extends WebSecurityConfigurerAdapter {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java
index bbe01aaf1d..6e2eb6804c 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java
@@ -114,26 +114,6 @@ public class HttpSecurityConfigurationTests {
 		this.mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()).andExpect(content().string("Bob"));
 	}
 
-	@RestController
-	static class NameController {
-
-		@GetMapping("/name")
-		public Callable name() {
-			return () -> SecurityContextHolder.getContext().getAuthentication().getName();
-		}
-
-	}
-
-	@EnableWebSecurity
-	static class DefaultWithFilterChainConfig {
-
-		@Bean
-		public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-			return http.build();
-		}
-
-	}
-
 	@Test
 	public void getWhenDefaultFilterChainBeanThenAnonymousPermitted() throws Exception {
 		this.spring.register(AuthorizeRequestsConfig.class, UserDetailsConfig.class, BaseController.class).autowire();
@@ -141,16 +121,6 @@ public class HttpSecurityConfigurationTests {
 		this.mockMvc.perform(get("/")).andExpect(status().isOk());
 	}
 
-	@EnableWebSecurity
-	static class AuthorizeRequestsConfig {
-
-		@Bean
-		public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-			return http.authorizeRequests(authorize -> authorize.anyRequest().permitAll()).build();
-		}
-
-	}
-
 	@Test
 	public void authenticateWhenDefaultFilterChainBeanThenSessionIdChanges() throws Exception {
 		this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
@@ -194,6 +164,36 @@ public class HttpSecurityConfigurationTests {
 		this.mockMvc.perform(get("/login")).andExpect(status().isOk());
 	}
 
+	@RestController
+	static class NameController {
+
+		@GetMapping("/name")
+		public Callable name() {
+			return () -> SecurityContextHolder.getContext().getAuthentication().getName();
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultWithFilterChainConfig {
+
+		@Bean
+		public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+			return http.build();
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class AuthorizeRequestsConfig {
+
+		@Bean
+		public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+			return http.authorizeRequests(authorize -> authorize.anyRequest().permitAll()).build();
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class SecurityEnabledConfig {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java
index 6a1edaec4f..08af641427 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java
@@ -133,6 +133,68 @@ public class OAuth2ClientConfigurationTests {
 		verify(accessTokenResponseClient, times(1)).getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class));
 	}
 
+	// gh-5321
+	@Test
+	public void loadContextWhenOAuth2AuthorizedClientRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
+		assertThatThrownBy(
+				() -> this.spring.register(OAuth2AuthorizedClientRepositoryRegisteredTwiceConfig.class).autowire())
+						.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
+						.hasMessageContaining("Expected single matching bean of type '"
+								+ OAuth2AuthorizedClientRepository.class.getName()
+								+ "' but found 2: authorizedClientRepository1,authorizedClientRepository2");
+	}
+
+	@Test
+	public void loadContextWhenClientRegistrationRepositoryNotRegisteredThenThrowNoSuchBeanDefinitionException() {
+		assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryNotRegisteredConfig.class).autowire())
+				.hasRootCauseInstanceOf(NoSuchBeanDefinitionException.class).hasMessageContaining(
+						"No qualifying bean of type '" + ClientRegistrationRepository.class.getName() + "' available");
+	}
+
+	@Test
+	public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
+		assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class)
+				.autowire()).hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).hasMessageContaining(
+						"expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2");
+	}
+
+	@Test
+	public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
+		assertThatThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire())
+				.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).hasMessageContaining(
+						"expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2");
+	}
+
+	// gh-8700
+	@Test
+	public void requestWhenAuthorizedClientManagerConfiguredThenUsed() throws Exception {
+		String clientRegistrationId = "client1";
+		String principalName = "user1";
+		TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
+
+		ClientRegistrationRepository clientRegistrationRepository = mock(ClientRegistrationRepository.class);
+		OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
+		OAuth2AuthorizedClientManager authorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
+
+		ClientRegistration clientRegistration = clientRegistration().registrationId(clientRegistrationId).build();
+		OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, principalName,
+				TestOAuth2AccessTokens.noScopes());
+
+		when(authorizedClientManager.authorize(any())).thenReturn(authorizedClient);
+
+		OAuth2AuthorizedClientManagerRegisteredConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
+		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
+		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
+		this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
+
+		this.mockMvc.perform(get("/authorized-client").with(authentication(authentication))).andExpect(status().isOk())
+				.andExpect(content().string("resolved"));
+
+		verify(authorizedClientManager).authorize(any());
+		verifyNoInteractions(clientRegistrationRepository);
+		verifyNoInteractions(authorizedClientRepository);
+	}
+
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class OAuth2AuthorizedClientArgumentResolverConfig extends WebSecurityConfigurerAdapter {
@@ -145,17 +207,6 @@ public class OAuth2ClientConfigurationTests {
 		protected void configure(HttpSecurity http) {
 		}
 
-		@RestController
-		public class Controller {
-
-			@GetMapping("/authorized-client")
-			public String authorizedClient(
-					@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
-				return authorizedClient != null ? "resolved" : "not-resolved";
-			}
-
-		}
-
 		@Bean
 		public ClientRegistrationRepository clientRegistrationRepository() {
 			return CLIENT_REGISTRATION_REPOSITORY;
@@ -171,17 +222,17 @@ public class OAuth2ClientConfigurationTests {
 			return ACCESS_TOKEN_RESPONSE_CLIENT;
 		}
 
-	}
+		@RestController
+		public class Controller {
+
+			@GetMapping("/authorized-client")
+			public String authorizedClient(
+					@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
+				return authorizedClient != null ? "resolved" : "not-resolved";
+			}
+
+		}
 
-	// gh-5321
-	@Test
-	public void loadContextWhenOAuth2AuthorizedClientRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
-		assertThatThrownBy(
-				() -> this.spring.register(OAuth2AuthorizedClientRepositoryRegisteredTwiceConfig.class).autowire())
-						.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
-						.hasMessageContaining("Expected single matching bean of type '"
-								+ OAuth2AuthorizedClientRepository.class.getName()
-								+ "' but found 2: authorizedClientRepository1,authorizedClientRepository2");
 	}
 
 	@EnableWebMvc
@@ -221,13 +272,6 @@ public class OAuth2ClientConfigurationTests {
 
 	}
 
-	@Test
-	public void loadContextWhenClientRegistrationRepositoryNotRegisteredThenThrowNoSuchBeanDefinitionException() {
-		assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryNotRegisteredConfig.class).autowire())
-				.hasRootCauseInstanceOf(NoSuchBeanDefinitionException.class).hasMessageContaining(
-						"No qualifying bean of type '" + ClientRegistrationRepository.class.getName() + "' available");
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class ClientRegistrationRepositoryNotRegisteredConfig extends WebSecurityConfigurerAdapter {
@@ -245,13 +289,6 @@ public class OAuth2ClientConfigurationTests {
 
 	}
 
-	@Test
-	public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
-		assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class)
-				.autowire()).hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).hasMessageContaining(
-						"expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2");
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class ClientRegistrationRepositoryRegisteredTwiceConfig extends WebSecurityConfigurerAdapter {
@@ -289,13 +326,6 @@ public class OAuth2ClientConfigurationTests {
 
 	}
 
-	@Test
-	public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
-		assertThatThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire())
-				.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).hasMessageContaining(
-						"expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2");
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class AccessTokenResponseClientRegisteredTwiceConfig extends WebSecurityConfigurerAdapter {
@@ -333,36 +363,6 @@ public class OAuth2ClientConfigurationTests {
 
 	}
 
-	// gh-8700
-	@Test
-	public void requestWhenAuthorizedClientManagerConfiguredThenUsed() throws Exception {
-		String clientRegistrationId = "client1";
-		String principalName = "user1";
-		TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
-
-		ClientRegistrationRepository clientRegistrationRepository = mock(ClientRegistrationRepository.class);
-		OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
-		OAuth2AuthorizedClientManager authorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
-
-		ClientRegistration clientRegistration = clientRegistration().registrationId(clientRegistrationId).build();
-		OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, principalName,
-				TestOAuth2AccessTokens.noScopes());
-
-		when(authorizedClientManager.authorize(any())).thenReturn(authorizedClient);
-
-		OAuth2AuthorizedClientManagerRegisteredConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
-		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
-		OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
-		this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
-
-		this.mockMvc.perform(get("/authorized-client").with(authentication(authentication))).andExpect(status().isOk())
-				.andExpect(content().string("resolved"));
-
-		verify(authorizedClientManager).authorize(any());
-		verifyNoInteractions(clientRegistrationRepository);
-		verifyNoInteractions(authorizedClientRepository);
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class OAuth2AuthorizedClientManagerRegisteredConfig extends WebSecurityConfigurerAdapter {
@@ -375,17 +375,6 @@ public class OAuth2ClientConfigurationTests {
 		protected void configure(HttpSecurity http) {
 		}
 
-		@RestController
-		public class Controller {
-
-			@GetMapping("/authorized-client")
-			public String authorizedClient(
-					@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
-				return authorizedClient != null ? "resolved" : "not-resolved";
-			}
-
-		}
-
 		@Bean
 		public ClientRegistrationRepository clientRegistrationRepository() {
 			return CLIENT_REGISTRATION_REPOSITORY;
@@ -401,6 +390,17 @@ public class OAuth2ClientConfigurationTests {
 			return AUTHORIZED_CLIENT_MANAGER;
 		}
 
+		@RestController
+		public class Controller {
+
+			@GetMapping("/authorized-client")
+			public String authorizedClient(
+					@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
+				return authorizedClient != null ? "resolved" : "not-resolved";
+			}
+
+		}
+
 	}
 
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/Sec2515Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/Sec2515Tests.java
index 744147312b..d81ecb80d0 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/Sec2515Tests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/Sec2515Tests.java
@@ -45,33 +45,11 @@ public class Sec2515Tests {
 		this.spring.register(StackOverflowSecurityConfig.class).autowire();
 	}
 
-	@EnableWebSecurity
-	static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
-
-		@Bean
-		@Override
-		public AuthenticationManager authenticationManagerBean() throws Exception {
-			return super.authenticationManagerBean();
-		}
-
-	}
-
 	@Test(expected = FatalBeanException.class)
 	public void loadConfigWhenAuthenticationManagerNotConfiguredAndRegisterBeanCustomNameThenThrowFatalBeanException() {
 		this.spring.register(CustomBeanNameStackOverflowSecurityConfig.class).autowire();
 	}
 
-	@EnableWebSecurity
-	static class CustomBeanNameStackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		@Bean(name = "custom")
-		public AuthenticationManager authenticationManagerBean() throws Exception {
-			return super.authenticationManagerBean();
-		}
-
-	}
-
 	// SEC-2549
 	@Test
 	public void loadConfigWhenChildClassLoaderSetThenContextLoads() {
@@ -83,6 +61,33 @@ public class Sec2515Tests {
 		this.spring.autowire();
 
 		assertThat(this.spring.getContext().getBean(AuthenticationManager.class)).isNotNull();
+	} // SEC-2515
+
+	@Test
+	public void loadConfigWhenAuthenticationManagerConfiguredAndRegisterBeanThenContextLoads() {
+		this.spring.register(SecurityConfig.class).autowire();
+	}
+
+	@EnableWebSecurity
+	static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
+
+		@Bean
+		@Override
+		public AuthenticationManager authenticationManagerBean() throws Exception {
+			return super.authenticationManagerBean();
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CustomBeanNameStackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		@Bean(name = "custom")
+		public AuthenticationManager authenticationManagerBean() throws Exception {
+			return super.authenticationManagerBean();
+		}
+
 	}
 
 	@EnableWebSecurity
@@ -98,12 +103,6 @@ public class Sec2515Tests {
 
 	}
 
-	// SEC-2515
-	@Test
-	public void loadConfigWhenAuthenticationManagerConfiguredAndRegisterBeanThenContextLoads() {
-		this.spring.register(SecurityConfig.class).autowire();
-	}
-
 	@EnableWebSecurity
 	static class SecurityConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java
index 1a86b00a1a..c5eb62cd68 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java
@@ -79,6 +79,9 @@ public class WebSecurityConfigurationTests {
 	@Rule
 	public final SpringTestRule spring = new SpringTestRule();
 
+	@Rule
+	public SpringTestRule child = new SpringTestRule();
+
 	@Autowired
 	private MockMvc mockMvc;
 
@@ -113,6 +116,177 @@ public class WebSecurityConfigurationTests {
 		assertThat(filterChains.get(5).matches(request)).isTrue();
 	}
 
+	@Test
+	public void loadConfigWhenSecurityFilterChainsHaveOrderThenFilterChainsOrdered() {
+		this.spring.register(SortedSecurityFilterChainConfig.class).autowire();
+
+		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
+		List filterChains = filterChainProxy.getFilterChains();
+		assertThat(filterChains).hasSize(4);
+
+		MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
+
+		request.setServletPath("/role1/**");
+		assertThat(filterChains.get(0).matches(request)).isTrue();
+
+		request.setServletPath("/role2/**");
+		assertThat(filterChains.get(1).matches(request)).isTrue();
+
+		request.setServletPath("/role3/**");
+		assertThat(filterChains.get(2).matches(request)).isTrue();
+
+		request.setServletPath("/**");
+		assertThat(filterChains.get(3).matches(request)).isTrue();
+	}
+
+	@Test
+	public void loadConfigWhenWebSecurityConfigurersHaveSameOrderThenThrowBeanCreationException() {
+		Throwable thrown = catchThrowable(() -> this.spring.register(DuplicateOrderConfig.class).autowire());
+
+		assertThat(thrown).isInstanceOf(BeanCreationException.class)
+				.hasMessageContaining("@Order on WebSecurityConfigurers must be unique")
+				.hasMessageContaining(DuplicateOrderConfig.WebConfigurer1.class.getName())
+				.hasMessageContaining(DuplicateOrderConfig.WebConfigurer2.class.getName());
+	}
+
+	@Test
+	public void loadConfigWhenWebInvocationPrivilegeEvaluatorSetThenIsRegistered() {
+		PrivilegeEvaluatorConfigurerAdapterConfig.PRIVILEGE_EVALUATOR = mock(WebInvocationPrivilegeEvaluator.class);
+
+		this.spring.register(PrivilegeEvaluatorConfigurerAdapterConfig.class).autowire();
+
+		assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
+				.isSameAs(PrivilegeEvaluatorConfigurerAdapterConfig.PRIVILEGE_EVALUATOR);
+	}
+
+	@Test
+	public void loadConfigWhenSecurityExpressionHandlerSetThenIsRegistered() {
+		WebSecurityExpressionHandlerConfig.EXPRESSION_HANDLER = mock(SecurityExpressionHandler.class);
+		when(WebSecurityExpressionHandlerConfig.EXPRESSION_HANDLER.getExpressionParser())
+				.thenReturn(mock(ExpressionParser.class));
+
+		this.spring.register(WebSecurityExpressionHandlerConfig.class).autowire();
+
+		assertThat(this.spring.getContext().getBean(SecurityExpressionHandler.class))
+				.isSameAs(WebSecurityExpressionHandlerConfig.EXPRESSION_HANDLER);
+	}
+
+	@Test
+	public void loadConfigWhenSecurityExpressionHandlerIsNullThenException() {
+		Throwable thrown = catchThrowable(
+				() -> this.spring.register(NullWebSecurityExpressionHandlerConfig.class).autowire());
+
+		assertThat(thrown).isInstanceOf(BeanCreationException.class);
+		assertThat(thrown).hasRootCauseExactlyInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void loadConfigWhenDefaultSecurityExpressionHandlerThenDefaultIsRegistered() {
+		this.spring.register(WebSecurityExpressionHandlerDefaultsConfig.class).autowire();
+
+		assertThat(this.spring.getContext().getBean(SecurityExpressionHandler.class))
+				.isInstanceOf(DefaultWebSecurityExpressionHandler.class);
+	}
+
+	@Test
+	public void securityExpressionHandlerWhenRoleHierarchyBeanThenRoleHierarchyUsed() {
+		this.spring.register(WebSecurityExpressionHandlerRoleHierarchyBeanConfig.class).autowire();
+		TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused", "ROLE_ADMIN");
+		FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest("GET", ""),
+				new MockHttpServletResponse(), new MockFilterChain());
+
+		AbstractSecurityExpressionHandler handler = this.spring.getContext()
+				.getBean(AbstractSecurityExpressionHandler.class);
+		EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
+		Expression expression = handler.getExpressionParser().parseExpression("hasRole('ROLE_USER')");
+		boolean granted = expression.getValue(evaluationContext, Boolean.class);
+		assertThat(granted).isTrue();
+	}
+
+	@Test
+	public void securityExpressionHandlerWhenPermissionEvaluatorBeanThenPermissionEvaluatorUsed() {
+		this.spring.register(WebSecurityExpressionHandlerPermissionEvaluatorBeanConfig.class).autowire();
+		TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused");
+		FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest("GET", ""),
+				new MockHttpServletResponse(), new MockFilterChain());
+
+		AbstractSecurityExpressionHandler handler = this.spring.getContext()
+				.getBean(AbstractSecurityExpressionHandler.class);
+		EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
+		Expression expression = handler.getExpressionParser().parseExpression("hasPermission(#study,'DELETE')");
+		boolean granted = expression.getValue(evaluationContext, Boolean.class);
+		assertThat(granted).isTrue();
+	}
+
+	@Test
+	public void loadConfigWhenDefaultWebInvocationPrivilegeEvaluatorThenDefaultIsRegistered() {
+		this.spring.register(WebInvocationPrivilegeEvaluatorDefaultsConfig.class).autowire();
+
+		assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
+				.isInstanceOf(DefaultWebInvocationPrivilegeEvaluator.class);
+	}
+
+	@Test
+	public void loadConfigWhenSecurityFilterChainBeanThenDefaultWebInvocationPrivilegeEvaluatorIsRegistered() {
+		this.spring.register(AuthorizeRequestsFilterChainConfig.class).autowire();
+
+		assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
+				.isInstanceOf(DefaultWebInvocationPrivilegeEvaluator.class);
+	}
+
+	// SEC-2303
+	@Test
+	public void loadConfigWhenDefaultSecurityExpressionHandlerThenBeanResolverSet() throws Exception {
+		this.spring.register(DefaultExpressionHandlerSetsBeanResolverConfig.class).autowire();
+
+		this.mockMvc.perform(get("/")).andExpect(status().isOk());
+		this.mockMvc.perform(post("/")).andExpect(status().isForbidden());
+	}
+
+	// SEC-2461
+	@Test
+	public void loadConfigWhenMultipleWebSecurityConfigurationThenContextLoads() {
+		this.spring.register(ParentConfig.class).autowire();
+
+		this.child.register(ChildConfig.class);
+		this.child.getContext().setParent(this.spring.getContext());
+		this.child.autowire();
+
+		assertThat(this.spring.getContext().getBean("springSecurityFilterChain")).isNotNull();
+		assertThat(this.child.getContext().getBean("springSecurityFilterChain")).isNotNull();
+
+		assertThat(this.spring.getContext().containsBean("springSecurityFilterChain")).isTrue();
+		assertThat(this.child.getContext().containsBean("springSecurityFilterChain")).isTrue();
+	}
+
+	// SEC-2773
+	@Test
+	public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationThenIsStatic() {
+		Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
+		assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
+	}
+
+	@Test
+	public void loadConfigWhenBeanProxyingEnabledAndSubclassThenFilterChainsCreated() {
+		this.spring.register(GlobalAuthenticationWebSecurityConfigurerAdaptersConfig.class, SubclassConfig.class)
+				.autowire();
+
+		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
+		List filterChains = filterChainProxy.getFilterChains();
+
+		assertThat(filterChains).hasSize(4);
+	}
+
+	@Test
+	public void loadConfigWhenBothAdapterAndFilterChainConfiguredThenException() {
+		Throwable thrown = catchThrowable(() -> this.spring.register(AdapterAndFilterChainConfig.class).autowire());
+
+		assertThat(thrown).isInstanceOf(BeanCreationException.class)
+				.hasRootCauseExactlyInstanceOf(IllegalStateException.class)
+				.hasMessageContaining("Found WebSecurityConfigurerAdapter as well as SecurityFilterChain.");
+
+	}
+
 	@EnableWebSecurity
 	@Import(AuthenticationTestConfiguration.class)
 	static class SortedWebSecurityConfigurerAdaptersConfig {
@@ -186,29 +360,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenSecurityFilterChainsHaveOrderThenFilterChainsOrdered() {
-		this.spring.register(SortedSecurityFilterChainConfig.class).autowire();
-
-		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
-		List filterChains = filterChainProxy.getFilterChains();
-		assertThat(filterChains).hasSize(4);
-
-		MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
-
-		request.setServletPath("/role1/**");
-		assertThat(filterChains.get(0).matches(request)).isTrue();
-
-		request.setServletPath("/role2/**");
-		assertThat(filterChains.get(1).matches(request)).isTrue();
-
-		request.setServletPath("/role3/**");
-		assertThat(filterChains.get(2).matches(request)).isTrue();
-
-		request.setServletPath("/**");
-		assertThat(filterChains.get(3).matches(request)).isTrue();
-	}
-
 	@EnableWebSecurity
 	@Import(AuthenticationTestConfiguration.class)
 	static class SortedSecurityFilterChainConfig {
@@ -241,16 +392,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenWebSecurityConfigurersHaveSameOrderThenThrowBeanCreationException() {
-		Throwable thrown = catchThrowable(() -> this.spring.register(DuplicateOrderConfig.class).autowire());
-
-		assertThat(thrown).isInstanceOf(BeanCreationException.class)
-				.hasMessageContaining("@Order on WebSecurityConfigurers must be unique")
-				.hasMessageContaining(DuplicateOrderConfig.WebConfigurer1.class.getName())
-				.hasMessageContaining(DuplicateOrderConfig.WebConfigurer2.class.getName());
-	}
-
 	@EnableWebSecurity
 	@Import(AuthenticationTestConfiguration.class)
 	static class DuplicateOrderConfig {
@@ -287,16 +428,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenWebInvocationPrivilegeEvaluatorSetThenIsRegistered() {
-		PrivilegeEvaluatorConfigurerAdapterConfig.PRIVILEGE_EVALUATOR = mock(WebInvocationPrivilegeEvaluator.class);
-
-		this.spring.register(PrivilegeEvaluatorConfigurerAdapterConfig.class).autowire();
-
-		assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
-				.isSameAs(PrivilegeEvaluatorConfigurerAdapterConfig.PRIVILEGE_EVALUATOR);
-	}
-
 	@EnableWebSecurity
 	static class PrivilegeEvaluatorConfigurerAdapterConfig extends WebSecurityConfigurerAdapter {
 
@@ -309,18 +440,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenSecurityExpressionHandlerSetThenIsRegistered() {
-		WebSecurityExpressionHandlerConfig.EXPRESSION_HANDLER = mock(SecurityExpressionHandler.class);
-		when(WebSecurityExpressionHandlerConfig.EXPRESSION_HANDLER.getExpressionParser())
-				.thenReturn(mock(ExpressionParser.class));
-
-		this.spring.register(WebSecurityExpressionHandlerConfig.class).autowire();
-
-		assertThat(this.spring.getContext().getBean(SecurityExpressionHandler.class))
-				.isSameAs(WebSecurityExpressionHandlerConfig.EXPRESSION_HANDLER);
-	}
-
 	@EnableWebSecurity
 	static class WebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
 
@@ -343,15 +462,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenSecurityExpressionHandlerIsNullThenException() {
-		Throwable thrown = catchThrowable(
-				() -> this.spring.register(NullWebSecurityExpressionHandlerConfig.class).autowire());
-
-		assertThat(thrown).isInstanceOf(BeanCreationException.class);
-		assertThat(thrown).hasRootCauseExactlyInstanceOf(IllegalArgumentException.class);
-	}
-
 	@EnableWebSecurity
 	static class NullWebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
 
@@ -362,14 +472,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenDefaultSecurityExpressionHandlerThenDefaultIsRegistered() {
-		this.spring.register(WebSecurityExpressionHandlerDefaultsConfig.class).autowire();
-
-		assertThat(this.spring.getContext().getBean(SecurityExpressionHandler.class))
-				.isInstanceOf(DefaultWebSecurityExpressionHandler.class);
-	}
-
 	@EnableWebSecurity
 	static class WebSecurityExpressionHandlerDefaultsConfig extends WebSecurityConfigurerAdapter {
 
@@ -384,21 +486,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void securityExpressionHandlerWhenRoleHierarchyBeanThenRoleHierarchyUsed() {
-		this.spring.register(WebSecurityExpressionHandlerRoleHierarchyBeanConfig.class).autowire();
-		TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused", "ROLE_ADMIN");
-		FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest("GET", ""),
-				new MockHttpServletResponse(), new MockFilterChain());
-
-		AbstractSecurityExpressionHandler handler = this.spring.getContext()
-				.getBean(AbstractSecurityExpressionHandler.class);
-		EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
-		Expression expression = handler.getExpressionParser().parseExpression("hasRole('ROLE_USER')");
-		boolean granted = expression.getValue(evaluationContext, Boolean.class);
-		assertThat(granted).isTrue();
-	}
-
 	@EnableWebSecurity
 	static class WebSecurityExpressionHandlerRoleHierarchyBeanConfig extends WebSecurityConfigurerAdapter {
 
@@ -411,21 +498,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void securityExpressionHandlerWhenPermissionEvaluatorBeanThenPermissionEvaluatorUsed() {
-		this.spring.register(WebSecurityExpressionHandlerPermissionEvaluatorBeanConfig.class).autowire();
-		TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused");
-		FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest("GET", ""),
-				new MockHttpServletResponse(), new MockFilterChain());
-
-		AbstractSecurityExpressionHandler handler = this.spring.getContext()
-				.getBean(AbstractSecurityExpressionHandler.class);
-		EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
-		Expression expression = handler.getExpressionParser().parseExpression("hasPermission(#study,'DELETE')");
-		boolean granted = expression.getValue(evaluationContext, Boolean.class);
-		assertThat(granted).isTrue();
-	}
-
 	@EnableWebSecurity
 	static class WebSecurityExpressionHandlerPermissionEvaluatorBeanConfig extends WebSecurityConfigurerAdapter {
 
@@ -449,14 +521,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenDefaultWebInvocationPrivilegeEvaluatorThenDefaultIsRegistered() {
-		this.spring.register(WebInvocationPrivilegeEvaluatorDefaultsConfig.class).autowire();
-
-		assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
-				.isInstanceOf(DefaultWebInvocationPrivilegeEvaluator.class);
-	}
-
 	@EnableWebSecurity
 	static class WebInvocationPrivilegeEvaluatorDefaultsConfig extends WebSecurityConfigurerAdapter {
 
@@ -471,14 +535,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenSecurityFilterChainBeanThenDefaultWebInvocationPrivilegeEvaluatorIsRegistered() {
-		this.spring.register(AuthorizeRequestsFilterChainConfig.class).autowire();
-
-		assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
-				.isInstanceOf(DefaultWebInvocationPrivilegeEvaluator.class);
-	}
-
 	@EnableWebSecurity
 	static class AuthorizeRequestsFilterChainConfig {
 
@@ -489,15 +545,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	// SEC-2303
-	@Test
-	public void loadConfigWhenDefaultSecurityExpressionHandlerThenBeanResolverSet() throws Exception {
-		this.spring.register(DefaultExpressionHandlerSetsBeanResolverConfig.class).autowire();
-
-		this.mockMvc.perform(get("/")).andExpect(status().isOk());
-		this.mockMvc.perform(post("/")).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class DefaultExpressionHandlerSetsBeanResolverConfig extends WebSecurityConfigurerAdapter {
 
@@ -510,6 +557,11 @@ public class WebSecurityConfigurationTests {
 			// @formatter:on
 		}
 
+		@Bean
+		public MyBean b() {
+			return new MyBean();
+		}
+
 		@RestController
 		public class HomeController {
 
@@ -520,11 +572,6 @@ public class WebSecurityConfigurationTests {
 
 		}
 
-		@Bean
-		public MyBean b() {
-			return new MyBean();
-		}
-
 		static class MyBean {
 
 			public boolean deny() {
@@ -539,25 +586,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Rule
-	public SpringTestRule child = new SpringTestRule();
-
-	// SEC-2461
-	@Test
-	public void loadConfigWhenMultipleWebSecurityConfigurationThenContextLoads() {
-		this.spring.register(ParentConfig.class).autowire();
-
-		this.child.register(ChildConfig.class);
-		this.child.getContext().setParent(this.spring.getContext());
-		this.child.autowire();
-
-		assertThat(this.spring.getContext().getBean("springSecurityFilterChain")).isNotNull();
-		assertThat(this.child.getContext().getBean("springSecurityFilterChain")).isNotNull();
-
-		assertThat(this.spring.getContext().containsBean("springSecurityFilterChain")).isTrue();
-		assertThat(this.child.getContext().containsBean("springSecurityFilterChain")).isTrue();
-	}
-
 	@EnableWebSecurity
 	static class ParentConfig extends WebSecurityConfigurerAdapter {
 
@@ -573,24 +601,6 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	// SEC-2773
-	@Test
-	public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationThenIsStatic() {
-		Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
-		assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
-	}
-
-	@Test
-	public void loadConfigWhenBeanProxyingEnabledAndSubclassThenFilterChainsCreated() {
-		this.spring.register(GlobalAuthenticationWebSecurityConfigurerAdaptersConfig.class, SubclassConfig.class)
-				.autowire();
-
-		FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
-		List filterChains = filterChainProxy.getFilterChains();
-
-		assertThat(filterChains).hasSize(4);
-	}
-
 	@Configuration
 	static class SubclassConfig extends WebSecurityConfiguration {
 
@@ -637,20 +647,17 @@ public class WebSecurityConfigurationTests {
 
 	}
 
-	@Test
-	public void loadConfigWhenBothAdapterAndFilterChainConfiguredThenException() {
-		Throwable thrown = catchThrowable(() -> this.spring.register(AdapterAndFilterChainConfig.class).autowire());
-
-		assertThat(thrown).isInstanceOf(BeanCreationException.class)
-				.hasRootCauseExactlyInstanceOf(IllegalStateException.class)
-				.hasMessageContaining("Found WebSecurityConfigurerAdapter as well as SecurityFilterChain.");
-
-	}
-
 	@EnableWebSecurity
 	@Import(AuthenticationTestConfiguration.class)
 	static class AdapterAndFilterChainConfig {
 
+		@Order(2)
+		@Bean
+		SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+			return http.antMatcher("/filter/**").authorizeRequests(authorize -> authorize.anyRequest().authenticated())
+					.build();
+		}
+
 		@Order(1)
 		@Configuration
 		static class WebConfigurer extends WebSecurityConfigurerAdapter {
@@ -662,13 +669,6 @@ public class WebSecurityConfigurationTests {
 
 		}
 
-		@Order(2)
-		@Bean
-		SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-			return http.antMatcher("/filter/**").authorizeRequests(authorize -> authorize.anyRequest().authenticated())
-					.build();
-		}
-
 	}
 
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
index 306fd90162..05d7c530bd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
@@ -55,6 +55,27 @@ public class AnonymousConfigurerTests {
 		this.mockMvc.perform(get("/")).andExpect(content().string("principal"));
 	}
 
+	@Test
+	public void requestWhenAnonymousPrincipalInLambdaThenPrincipalUsed() throws Exception {
+		this.spring.register(AnonymousPrincipalInLambdaConfig.class, PrincipalController.class).autowire();
+
+		this.mockMvc.perform(get("/")).andExpect(content().string("principal"));
+	}
+
+	@Test
+	public void requestWhenAnonymousDisabledInLambdaThenRespondsWithForbidden() throws Exception {
+		this.spring.register(AnonymousDisabledInLambdaConfig.class, PrincipalController.class).autowire();
+
+		this.mockMvc.perform(get("/")).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void requestWhenAnonymousWithDefaultsInLambdaThenRespondsWithOk() throws Exception {
+		this.spring.register(AnonymousWithDefaultsInLambdaConfig.class, PrincipalController.class).autowire();
+
+		this.mockMvc.perform(get("/")).andExpect(status().isOk());
+	}
+
 	@EnableWebSecurity
 	@EnableWebMvc
 	static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@@ -73,13 +94,6 @@ public class AnonymousConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenAnonymousPrincipalInLambdaThenPrincipalUsed() throws Exception {
-		this.spring.register(AnonymousPrincipalInLambdaConfig.class, PrincipalController.class).autowire();
-
-		this.mockMvc.perform(get("/")).andExpect(content().string("principal"));
-	}
-
 	@EnableWebSecurity
 	@EnableWebMvc
 	static class AnonymousPrincipalInLambdaConfig extends WebSecurityConfigurerAdapter {
@@ -97,13 +111,6 @@ public class AnonymousConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenAnonymousDisabledInLambdaThenRespondsWithForbidden() throws Exception {
-		this.spring.register(AnonymousDisabledInLambdaConfig.class, PrincipalController.class).autowire();
-
-		this.mockMvc.perform(get("/")).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class AnonymousDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -130,13 +137,6 @@ public class AnonymousConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenAnonymousWithDefaultsInLambdaThenRespondsWithOk() throws Exception {
-		this.spring.register(AnonymousWithDefaultsInLambdaConfig.class, PrincipalController.class).autowire();
-
-		this.mockMvc.perform(get("/")).andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class AnonymousWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
index f2388b2184..fca0698300 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
@@ -99,29 +99,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.antMatchers(HttpMethod.POST).denyAll();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void postWhenPostDenyAllInLambdaThenRespondsWithForbidden() throws Exception {
 		loadConfig(AntMatchersNoPatternsInLambdaConfig.class);
@@ -132,31 +109,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	static class AntMatchersNoPatternsInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests(authorizeRequests ->
-					authorizeRequests
-						.antMatchers(HttpMethod.POST).denyAll()
-				);
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-2256
 	@Test
 	public void antMatchersPathVariables() throws Exception {
@@ -195,30 +147,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	static class AntPatchersPathVariables extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-				.requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'")
-				.anyRequest().denyAll();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-	}
-
 	// gh-3786
 	@Test
 	public void antMatchersPathVariablesCaseInsensitiveCamelCaseVariables() throws Exception {
@@ -238,30 +166,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	static class AntMatchersPathVariablesCamelCaseVariables extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-				.requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'")
-				.anyRequest().denyAll();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-	}
-
 	// gh-3394
 	@Test
 	public void roleHiearchy() throws Exception {
@@ -278,36 +182,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	static class RoleHiearchyConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("ADMIN");
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@Bean
-		public RoleHierarchy roleHiearchy() {
-			RoleHierarchyImpl result = new RoleHierarchyImpl();
-			result.setHierarchy("ROLE_USER > ROLE_ADMIN");
-			return result;
-		}
-
-	}
-
 	@Test
 	public void mvcMatcher() throws Exception {
 		loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
@@ -332,41 +206,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	@EnableWebMvc
-	static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic().and()
-				.authorizeRequests()
-					.mvcMatchers("/path").denyAll();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@RestController
-		static class PathController {
-
-			@RequestMapping("/path")
-			public String path() {
-				return "path";
-			}
-
-		}
-
-	}
-
 	@Test
 	public void requestWhenMvcMatcherDenyAllThenRespondsWithUnauthorized() throws Exception {
 		loadConfig(MvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
@@ -391,121 +230,6 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	@EnableWebMvc
-	static class MvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic(withDefaults())
-				.authorizeRequests(authorizeRequests ->
-					authorizeRequests
-						.mvcMatchers("/path").denyAll()
-				);
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@RestController
-		static class PathController {
-
-			@RequestMapping("/path")
-			public String path() {
-				return "path";
-			}
-
-		}
-
-	}
-
-	@Test
-	public void mvcMatcherServletPath() throws Exception {
-		loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path.html");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path/");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/foo");
-		this.request.setRequestURI("/foo/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		setup();
-
-		this.request.setServletPath("/");
-		this.request.setRequestURI("/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-	}
-
-	@EnableWebSecurity
-	@Configuration
-	@EnableWebMvc
-	static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic().and()
-				.authorizeRequests()
-					.mvcMatchers("/path").servletPath("/spring").denyAll();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@RestController
-		static class PathController {
-
-			@RequestMapping("/path")
-			public String path() {
-				return "path";
-			}
-
-		}
-
-	}
-
 	@Test
 	public void requestWhenMvcMatcherServletPathDenyAllThenMatchesOnServletPath() throws Exception {
 		loadConfig(MvcMatcherServletPathInLambdaConfig.class, LegacyMvcMatchingConfig.class);
@@ -549,6 +273,327 @@ public class AuthorizeRequestsTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
 	}
 
+	@Test
+	public void mvcMatcherPathVariables() throws Exception {
+		loadConfig(MvcMatcherPathVariablesConfig.class);
+
+		this.request.setRequestURI("/user/user");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		this.setup();
+		this.request.setRequestURI("/user/deny");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+	}
+
+	@Test
+	public void requestWhenMvcMatcherPathVariablesThenMatchesOnPathVariables() throws Exception {
+		loadConfig(MvcMatcherPathVariablesInLambdaConfig.class);
+
+		this.request.setRequestURI("/user/user");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		this.setup();
+		this.request.setRequestURI("/user/deny");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+	}
+
+	@Test
+	public void mvcMatcherServletPath() throws Exception {
+		loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path.html");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path/");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/foo");
+		this.request.setRequestURI("/foo/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		setup();
+
+		this.request.setServletPath("/");
+		this.request.setRequestURI("/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+	}
+
+	public void loadConfig(Class... configs) {
+		this.context = new AnnotationConfigWebApplicationContext();
+		this.context.register(configs);
+		this.context.setServletContext(this.servletContext);
+		this.context.refresh();
+
+		this.context.getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.antMatchers(HttpMethod.POST).denyAll();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	static class AntMatchersNoPatternsInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.antMatchers(HttpMethod.POST).denyAll()
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	static class AntPatchersPathVariables extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+				.requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'")
+				.anyRequest().denyAll();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	static class AntMatchersPathVariablesCamelCaseVariables extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+				.requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'")
+				.anyRequest().denyAll();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	static class RoleHiearchyConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("ADMIN");
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@Bean
+		public RoleHierarchy roleHiearchy() {
+			RoleHierarchyImpl result = new RoleHierarchyImpl();
+			result.setHierarchy("ROLE_USER > ROLE_ADMIN");
+			return result;
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	@EnableWebMvc
+	static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic().and()
+				.authorizeRequests()
+					.mvcMatchers("/path").denyAll();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@RestController
+		static class PathController {
+
+			@RequestMapping("/path")
+			public String path() {
+				return "path";
+			}
+
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	@EnableWebMvc
+	static class MvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic(withDefaults())
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.mvcMatchers("/path").denyAll()
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@RestController
+		static class PathController {
+
+			@RequestMapping("/path")
+			public String path() {
+				return "path";
+			}
+
+		}
+
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	@EnableWebMvc
+	static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic().and()
+				.authorizeRequests()
+					.mvcMatchers("/path").servletPath("/spring").denyAll();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@RestController
+		static class PathController {
+
+			@RequestMapping("/path")
+			public String path() {
+				return "path";
+			}
+
+		}
+
+	}
+
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -586,24 +631,6 @@ public class AuthorizeRequestsTests {
 
 	}
 
-	@Test
-	public void mvcMatcherPathVariables() throws Exception {
-		loadConfig(MvcMatcherPathVariablesConfig.class);
-
-		this.request.setRequestURI("/user/user");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		this.setup();
-		this.request.setRequestURI("/user/deny");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -639,24 +666,6 @@ public class AuthorizeRequestsTests {
 
 	}
 
-	@Test
-	public void requestWhenMvcMatcherPathVariablesThenMatchesOnPathVariables() throws Exception {
-		loadConfig(MvcMatcherPathVariablesInLambdaConfig.class);
-
-		this.request.setRequestURI("/user/user");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		this.setup();
-		this.request.setRequestURI("/user/deny");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -739,13 +748,4 @@ public class AuthorizeRequestsTests {
 
 	}
 
-	public void loadConfig(Class... configs) {
-		this.context = new AnnotationConfigWebApplicationContext();
-		this.context.register(configs);
-		this.context.setServletContext(this.servletContext);
-		this.context.refresh();
-
-		this.context.getAutowireCapableBeanFactory().autowireBean(this);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
index d448f8e3cd..c385a6aacb 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
@@ -84,6 +84,20 @@ public class ChannelSecurityConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ChannelProcessingFilter.class));
 	}
 
+	@Test
+	public void requiresChannelWhenInvokesTwiceThenUsesOriginalRequiresSecure() throws Exception {
+		this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("https://localhost/"));
+	}
+
+	@Test
+	public void requestWhenRequiresChannelConfiguredInLambdaThenRedirectsToHttps() throws Exception {
+		this.spring.register(RequiresChannelInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("https://localhost/"));
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -114,13 +128,6 @@ public class ChannelSecurityConfigurerTests {
 
 	}
 
-	@Test
-	public void requiresChannelWhenInvokesTwiceThenUsesOriginalRequiresSecure() throws Exception {
-		this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("https://localhost/"));
-	}
-
 	@EnableWebSecurity
 	static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
@@ -137,13 +144,6 @@ public class ChannelSecurityConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenRequiresChannelConfiguredInLambdaThenRedirectsToHttps() throws Exception {
-		this.spring.register(RequiresChannelInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("https://localhost/"));
-	}
-
 	@EnableWebSecurity
 	static class RequiresChannelInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
index 0311831080..c883479ace 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
@@ -70,22 +70,6 @@ public class CorsConfigurerTests {
 						"Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext");
 	}
 
-	@EnableWebSecurity
-	static class DefaultCorsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.cors();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
 		this.spring.register(MvcCorsConfig.class).autowire();
@@ -106,6 +90,124 @@ public class CorsConfigurerTests {
 				.andExpect(header().exists("X-Content-Type-Options"));
 	}
 
+	@Test
+	public void getWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(MvcCorsInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void optionsWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(MvcCorsInLambdaConfig.class).autowire();
+
+		this.mvc.perform(options("/")
+				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(ConfigSourceConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void optionsWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(ConfigSourceConfig.class).autowire();
+
+		this.mvc.perform(options("/")
+				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void getWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
+			throws Exception {
+		this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void optionsWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
+			throws Exception {
+		this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
+
+		this.mvc.perform(options("/")
+				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(CorsFilterConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void optionsWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(CorsFilterConfig.class).autowire();
+
+		this.mvc.perform(options("/")
+				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void getWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(CorsFilterInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@Test
+	public void optionsWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+		this.spring.register(CorsFilterInLambdaConfig.class).autowire();
+
+		this.mvc.perform(options("/")
+				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
+				.andExpect(header().exists("Access-Control-Allow-Origin"))
+				.andExpect(header().exists("X-Content-Type-Options"));
+	}
+
+	@EnableWebSecurity
+	static class DefaultCorsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.cors();
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class MvcCorsConfig extends WebSecurityConfigurerAdapter {
@@ -134,26 +236,6 @@ public class CorsConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(MvcCorsInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
-	@Test
-	public void optionsWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(MvcCorsInLambdaConfig.class).autowire();
-
-		this.mvc.perform(options("/")
-				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
-				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	static class MvcCorsInLambdaConfig extends WebSecurityConfigurerAdapter {
@@ -183,26 +265,6 @@ public class CorsConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(ConfigSourceConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
-	@Test
-	public void optionsWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(ConfigSourceConfig.class).autowire();
-
-		this.mvc.perform(options("/")
-				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
-				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
 	@EnableWebSecurity
 	static class ConfigSourceConfig extends WebSecurityConfigurerAdapter {
 
@@ -229,28 +291,6 @@ public class CorsConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
-			throws Exception {
-		this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
-	@Test
-	public void optionsWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
-			throws Exception {
-		this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
-
-		this.mvc.perform(options("/")
-				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
-				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
 	@EnableWebSecurity
 	static class ConfigSourceInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -278,26 +318,6 @@ public class CorsConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(CorsFilterConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
-	@Test
-	public void optionsWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(CorsFilterConfig.class).autowire();
-
-		this.mvc.perform(options("/")
-				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
-				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
 	@EnableWebSecurity
 	static class CorsFilterConfig extends WebSecurityConfigurerAdapter {
 
@@ -324,26 +344,6 @@ public class CorsConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(CorsFilterInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
-	@Test
-	public void optionsWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
-		this.spring.register(CorsFilterInLambdaConfig.class).autowire();
-
-		this.mvc.perform(options("/")
-				.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
-				.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
-				.andExpect(header().exists("Access-Control-Allow-Origin"))
-				.andExpect(header().exists("X-Content-Type-Options"));
-	}
-
 	@EnableWebSecurity
 	static class CorsFilterInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
index 9825c8ea99..bba69c31a7 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
@@ -56,6 +56,40 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
 		this.mvc.perform(post("/path")).andExpect(status().isOk());
 	}
 
+	@Test
+	public void requestWhenIgnoringRequestMatchersInLambdaThenAugmentedByConfiguredRequestMatcher() throws Exception {
+		this.spring.register(IgnoringRequestInLambdaMatchers.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/path")).andExpect(status().isForbidden());
+
+		this.mvc.perform(post("/path")).andExpect(status().isOk());
+	}
+
+	@Test
+	public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers() throws Exception {
+
+		this.spring.register(IgnoringPathsAndMatchers.class, BasicController.class).autowire();
+
+		this.mvc.perform(put("/csrf")).andExpect(status().isForbidden());
+
+		this.mvc.perform(post("/csrf")).andExpect(status().isOk());
+
+		this.mvc.perform(put("/no-csrf")).andExpect(status().isOk());
+	}
+
+	@Test
+	public void requestWhenIgnoringRequestMatcherInLambdaThenUnionsWithConfiguredIgnoringAntMatchers()
+			throws Exception {
+
+		this.spring.register(IgnoringPathsAndMatchersInLambdaConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(put("/csrf")).andExpect(status().isForbidden());
+
+		this.mvc.perform(post("/csrf")).andExpect(status().isOk());
+
+		this.mvc.perform(put("/no-csrf")).andExpect(status().isOk());
+	}
+
 	@EnableWebSecurity
 	static class IgnoringRequestMatchers extends WebSecurityConfigurerAdapter {
 
@@ -73,15 +107,6 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestWhenIgnoringRequestMatchersInLambdaThenAugmentedByConfiguredRequestMatcher() throws Exception {
-		this.spring.register(IgnoringRequestInLambdaMatchers.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/path")).andExpect(status().isForbidden());
-
-		this.mvc.perform(post("/path")).andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class IgnoringRequestInLambdaMatchers extends WebSecurityConfigurerAdapter {
 
@@ -101,18 +126,6 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers() throws Exception {
-
-		this.spring.register(IgnoringPathsAndMatchers.class, BasicController.class).autowire();
-
-		this.mvc.perform(put("/csrf")).andExpect(status().isForbidden());
-
-		this.mvc.perform(post("/csrf")).andExpect(status().isOk());
-
-		this.mvc.perform(put("/no-csrf")).andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class IgnoringPathsAndMatchers extends WebSecurityConfigurerAdapter {
 
@@ -130,19 +143,6 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestWhenIgnoringRequestMatcherInLambdaThenUnionsWithConfiguredIgnoringAntMatchers()
-			throws Exception {
-
-		this.spring.register(IgnoringPathsAndMatchersInLambdaConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(put("/csrf")).andExpect(status().isForbidden());
-
-		this.mvc.perform(post("/csrf")).andExpect(status().isOk());
-
-		this.mvc.perform(put("/no-csrf")).andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class IgnoringPathsAndMatchersInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerNoWebMvcTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerNoWebMvcTests.java
index 74e98391d9..1a5a64cfbb 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerNoWebMvcTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerNoWebMvcTests.java
@@ -68,6 +68,13 @@ public class CsrfConfigurerNoWebMvcTests {
 				.isNotEqualTo(CsrfRequestDataValueProcessor.class);
 	}
 
+	private void loadContext(Class configs) {
+		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
+		annotationConfigApplicationContext.register(configs);
+		annotationConfigApplicationContext.refresh();
+		this.context = annotationConfigApplicationContext;
+	}
+
 	@EnableWebSecurity
 	static class EnableWebConfig extends WebSecurityConfigurerAdapter {
 
@@ -97,11 +104,4 @@ public class CsrfConfigurerNoWebMvcTests {
 
 	}
 
-	private void loadContext(Class configs) {
-		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
-		annotationConfigApplicationContext.register(configs);
-		annotationConfigApplicationContext.refresh();
-		this.context = annotationConfigApplicationContext;
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
index 95f4585d44..4aa9547949 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
@@ -179,27 +179,6 @@ public class CsrfConfigurerTests {
 		assertThat(this.spring.getContext().getBean(RequestDataValueProcessor.class)).isNotNull();
 	}
 
-	@Configuration
-	static class AllowHttpMethodsFirewallConfig {
-
-		@Bean
-		StrictHttpFirewall strictHttpFirewall() {
-			StrictHttpFirewall result = new StrictHttpFirewall();
-			result.setUnsafeAllowAnyHttpMethod(true);
-			return result;
-		}
-
-	}
-
-	@EnableWebSecurity
-	static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) {
-		}
-
-	}
-
 	@Test
 	public void postWhenCsrfDisabledThenRespondsWithOk() throws Exception {
 		this.spring.register(DisableCsrfConfig.class, BasicController.class).autowire();
@@ -207,20 +186,6 @@ public class CsrfConfigurerTests {
 		this.mvc.perform(post("/")).andExpect(status().isOk());
 	}
 
-	@EnableWebSecurity
-	static class DisableCsrfConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf()
-					.disable();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void postWhenCsrfDisabledInLambdaThenRespondsWithOk() throws Exception {
 		this.spring.register(DisableCsrfInLambdaConfig.class, BasicController.class).autowire();
@@ -228,19 +193,6 @@ public class CsrfConfigurerTests {
 		this.mvc.perform(post("/")).andExpect(status().isOk());
 	}
 
-	@EnableWebSecurity
-	static class DisableCsrfInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf(AbstractHttpConfigurer::disable);
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-2498
 	@Test
 	public void loginWhenCsrfDisabledThenRedirectsToPreviousPostRequest() throws Exception {
@@ -253,34 +205,6 @@ public class CsrfConfigurerTests {
 				.andExpect(redirectedUrl("http://localhost/to-save"));
 	}
 
-	@EnableWebSecurity
-	static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.formLogin()
-					.and()
-				.csrf()
-					.disable();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-				.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginWhenCsrfEnabledThenDoesNotRedirectToPreviousPostRequest() throws Exception {
 		CsrfDisablesPostRequestFromRequestCacheConfig.REPO = mock(CsrfTokenRepository.class);
@@ -315,36 +239,6 @@ public class CsrfConfigurerTests {
 				.loadToken(any(HttpServletRequest.class));
 	}
 
-	@EnableWebSecurity
-	static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
-
-		static CsrfTokenRepository REPO;
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.formLogin()
-					.and()
-				.csrf()
-					.csrfTokenRepository(REPO);
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-2422
 	@Test
 	public void postWhenCsrfEnabledAndSessionIsExpiredThenRespondsWithForbidden() throws Exception {
@@ -357,22 +251,6 @@ public class CsrfConfigurerTests {
 				.andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf()
-					.and()
-				.sessionManagement()
-					.invalidSessionUrl("/error/sessionError");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requireCsrfProtectionMatcherWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
 		this.spring.register(RequireCsrfProtectionMatcherConfig.class, BasicController.class).autowire();
@@ -390,22 +268,6 @@ public class CsrfConfigurerTests {
 		this.mvc.perform(get("/")).andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
-
-		static RequestMatcher MATCHER;
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf()
-					.requireCsrfProtectionMatcher(MATCHER);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requireCsrfProtectionMatcherInLambdaWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
 		RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
@@ -424,21 +286,6 @@ public class CsrfConfigurerTests {
 		this.mvc.perform(get("/")).andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class RequireCsrfProtectionMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		static RequestMatcher MATCHER;
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf(csrf -> csrf.requireCsrfProtectionMatcher(MATCHER));
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenCustomCsrfTokenRepositoryThenRepositoryIsUsed() throws Exception {
 		CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
@@ -476,6 +323,247 @@ public class CsrfConfigurerTests {
 				any(HttpServletResponse.class));
 	}
 
+	@Test
+	public void getWhenCustomCsrfTokenRepositoryInLambdaThenRepositoryIsUsed() throws Exception {
+		CsrfTokenRepositoryInLambdaConfig.REPO = mock(CsrfTokenRepository.class);
+		when(CsrfTokenRepositoryInLambdaConfig.REPO.loadToken(any()))
+				.thenReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
+		this.spring.register(CsrfTokenRepositoryInLambdaConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isOk());
+		verify(CsrfTokenRepositoryInLambdaConfig.REPO).loadToken(any(HttpServletRequest.class));
+	}
+
+	@Test
+	public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
+		AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);
+		this.spring.register(AccessDeniedHandlerConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(post("/")).andExpect(status().isOk());
+
+		verify(AccessDeniedHandlerConfig.DENIED_HANDLER).handle(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any());
+	}
+
+	@Test
+	public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
+		this.spring.register(FormLoginConfig.class).autowire();
+
+		this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
+				.andExpect(status().isForbidden()).andExpect(unauthenticated());
+	}
+
+	@Test
+	public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
+		this.spring.register(FormLoginConfig.class).autowire();
+
+		this.mvc.perform(post("/logout").with(user("username"))).andExpect(status().isForbidden())
+				.andExpect(authenticated());
+	}
+
+	// SEC-2543
+	@Test
+	public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception {
+		this.spring.register(FormLoginConfig.class).autowire();
+
+		this.mvc.perform(get("/logout").with(user("username"))).andExpect(authenticated());
+	}
+
+	@Test
+	public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception {
+		this.spring.register(LogoutAllowsGetConfig.class).autowire();
+
+		this.mvc.perform(get("/logout").with(user("username"))).andExpect(unauthenticated());
+	}
+
+	// SEC-2749
+	@Test
+	public void configureWhenRequireCsrfProtectionMatcherNullThenException() {
+		assertThatThrownBy(() -> this.spring.register(NullRequireCsrfProtectionMatcherConfig.class).autowire())
+				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void getWhenDefaultCsrfTokenRepositoryThenDoesNotCreateSession() throws Exception {
+		this.spring.register(DefaultDoesNotCreateSession.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/")).andReturn();
+
+		assertThat(mvcResult.getRequest().getSession(false)).isNull();
+	}
+
+	@Test
+	public void getWhenNullAuthenticationStrategyThenException() {
+		assertThatThrownBy(() -> this.spring.register(NullAuthenticationStrategy.class).autowire())
+				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception {
+		CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class);
+
+		this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire();
+
+		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
+				.andExpect(redirectedUrl("/"));
+
+		verify(CsrfAuthenticationStrategyConfig.STRATEGY, atLeastOnce()).onAuthentication(any(Authentication.class),
+				any(HttpServletRequest.class), any(HttpServletResponse.class));
+	}
+
+	@Configuration
+	static class AllowHttpMethodsFirewallConfig {
+
+		@Bean
+		StrictHttpFirewall strictHttpFirewall() {
+			StrictHttpFirewall result = new StrictHttpFirewall();
+			result.setUnsafeAllowAnyHttpMethod(true);
+			return result;
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) {
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DisableCsrfConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf()
+					.disable();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DisableCsrfInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf(AbstractHttpConfigurer::disable);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.formLogin()
+					.and()
+				.csrf()
+					.disable();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+				.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
+
+		static CsrfTokenRepository REPO;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.formLogin()
+					.and()
+				.csrf()
+					.csrfTokenRepository(REPO);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf()
+					.and()
+				.sessionManagement()
+					.invalidSessionUrl("/error/sessionError");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
+
+		static RequestMatcher MATCHER;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf()
+					.requireCsrfProtectionMatcher(MATCHER);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RequireCsrfProtectionMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		static RequestMatcher MATCHER;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf(csrf -> csrf.requireCsrfProtectionMatcher(MATCHER));
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class CsrfTokenRepositoryConfig extends WebSecurityConfigurerAdapter {
 
@@ -503,17 +591,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCustomCsrfTokenRepositoryInLambdaThenRepositoryIsUsed() throws Exception {
-		CsrfTokenRepositoryInLambdaConfig.REPO = mock(CsrfTokenRepository.class);
-		when(CsrfTokenRepositoryInLambdaConfig.REPO.loadToken(any()))
-				.thenReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
-		this.spring.register(CsrfTokenRepositoryInLambdaConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isOk());
-		verify(CsrfTokenRepositoryInLambdaConfig.REPO).loadToken(any(HttpServletRequest.class));
-	}
-
 	@EnableWebSecurity
 	static class CsrfTokenRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -530,17 +607,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
-		AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);
-		this.spring.register(AccessDeniedHandlerConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(post("/")).andExpect(status().isOk());
-
-		verify(AccessDeniedHandlerConfig.DENIED_HANDLER).handle(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any());
-	}
-
 	@EnableWebSecurity
 	static class AccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
 
@@ -557,30 +623,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
-		this.spring.register(FormLoginConfig.class).autowire();
-
-		this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
-				.andExpect(status().isForbidden()).andExpect(unauthenticated());
-	}
-
-	@Test
-	public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
-		this.spring.register(FormLoginConfig.class).autowire();
-
-		this.mvc.perform(post("/logout").with(user("username"))).andExpect(status().isForbidden())
-				.andExpect(authenticated());
-	}
-
-	// SEC-2543
-	@Test
-	public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception {
-		this.spring.register(FormLoginConfig.class).autowire();
-
-		this.mvc.perform(get("/logout").with(user("username"))).andExpect(authenticated());
-	}
-
 	@EnableWebSecurity
 	static class FormLoginConfig extends WebSecurityConfigurerAdapter {
 
@@ -594,13 +636,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception {
-		this.spring.register(LogoutAllowsGetConfig.class).autowire();
-
-		this.mvc.perform(get("/logout").with(user("username"))).andExpect(unauthenticated());
-	}
-
 	@EnableWebSecurity
 	static class LogoutAllowsGetConfig extends WebSecurityConfigurerAdapter {
 
@@ -617,13 +652,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	// SEC-2749
-	@Test
-	public void configureWhenRequireCsrfProtectionMatcherNullThenException() {
-		assertThatThrownBy(() -> this.spring.register(NullRequireCsrfProtectionMatcherConfig.class).autowire())
-				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
-	}
-
 	@EnableWebSecurity
 	static class NullRequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
 
@@ -638,15 +666,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenDefaultCsrfTokenRepositoryThenDoesNotCreateSession() throws Exception {
-		this.spring.register(DefaultDoesNotCreateSession.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/")).andReturn();
-
-		assertThat(mvcResult.getRequest().getSession(false)).isNull();
-	}
-
 	@EnableWebSecurity
 	static class DefaultDoesNotCreateSession extends WebSecurityConfigurerAdapter {
 
@@ -688,12 +707,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenNullAuthenticationStrategyThenException() {
-		assertThatThrownBy(() -> this.spring.register(NullAuthenticationStrategy.class).autowire())
-				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
-	}
-
 	@EnableWebSecurity
 	static class CsrfAuthenticationStrategyConfig extends WebSecurityConfigurerAdapter {
 
@@ -721,19 +734,6 @@ public class CsrfConfigurerTests {
 
 	}
 
-	@Test
-	public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception {
-		CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class);
-
-		this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire();
-
-		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
-				.andExpect(redirectedUrl("/"));
-
-		verify(CsrfAuthenticationStrategyConfig.STRATEGY, atLeastOnce()).onAuthentication(any(Authentication.class),
-				any(HttpServletRequest.class), any(HttpServletResponse.class));
-	}
-
 	@RestController
 	static class BasicController {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java
index 716027edf0..0de52befb4 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java
@@ -77,20 +77,6 @@ public class DefaultFiltersTests {
 		assertThat(this.spring.getContext().getBean(FilterChainProxy.class)).isNotNull();
 	}
 
-	@EnableWebSecurity
-	static class FilterChainProxyBuilderMissingConfig {
-
-		@Autowired
-		public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser("user").password("password").roles("USER");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void nullWebInvocationPrivilegeEvaluator() {
 		this.spring.register(NullWebInvocationPrivilegeEvaluatorConfig.class, UserDetailsServiceConfig.class);
@@ -105,30 +91,6 @@ public class DefaultFiltersTests {
 		assertThat(filter).isEqualTo(1);
 	}
 
-	@Configuration
-	static class UserDetailsServiceConfig {
-
-		@Bean
-		public UserDetailsService userDetailsService() {
-			return new InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin());
-		}
-
-	}
-
-	@EnableWebSecurity
-	static class NullWebInvocationPrivilegeEvaluatorConfig extends WebSecurityConfigurerAdapter {
-
-		NullWebInvocationPrivilegeEvaluatorConfig() {
-			super(true);
-		}
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			http.formLogin();
-		}
-
-	}
-
 	@Test
 	public void filterChainProxyBuilderIgnoringResources() {
 		this.spring.register(FilterChainProxyBuilderIgnoringConfig.class, UserDetailsServiceConfig.class);
@@ -156,6 +118,60 @@ public class DefaultFiltersTests {
 		assertThat(classes.contains(FilterSecurityInterceptor.class)).isTrue();
 	}
 
+	@Test
+	public void defaultFiltersPermitAll() throws IOException, ServletException {
+		this.spring.register(DefaultFiltersConfigPermitAll.class, UserDetailsServiceConfig.class);
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		MockHttpServletRequest request = new MockHttpServletRequest("POST", "");
+		request.setServletPath("/logout");
+
+		CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
+		new HttpSessionCsrfTokenRepository().saveToken(csrfToken, request, response);
+		request.setParameter(csrfToken.getParameterName(), csrfToken.getToken());
+
+		this.spring.getContext().getBean("springSecurityFilterChain", Filter.class).doFilter(request, response,
+				new MockFilterChain());
+		assertThat(response.getRedirectedUrl()).isEqualTo("/login?logout");
+	}
+
+	@EnableWebSecurity
+	static class FilterChainProxyBuilderMissingConfig {
+
+		@Autowired
+		public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser("user").password("password").roles("USER");
+			// @formatter:on
+		}
+
+	}
+
+	@Configuration
+	static class UserDetailsServiceConfig {
+
+		@Bean
+		public UserDetailsService userDetailsService() {
+			return new InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin());
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NullWebInvocationPrivilegeEvaluatorConfig extends WebSecurityConfigurerAdapter {
+
+		NullWebInvocationPrivilegeEvaluatorConfig() {
+			super(true);
+		}
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http.formLogin();
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class FilterChainProxyBuilderIgnoringConfig extends WebSecurityConfigurerAdapter {
 
@@ -179,22 +195,6 @@ public class DefaultFiltersTests {
 
 	}
 
-	@Test
-	public void defaultFiltersPermitAll() throws IOException, ServletException {
-		this.spring.register(DefaultFiltersConfigPermitAll.class, UserDetailsServiceConfig.class);
-		MockHttpServletResponse response = new MockHttpServletResponse();
-		MockHttpServletRequest request = new MockHttpServletRequest("POST", "");
-		request.setServletPath("/logout");
-
-		CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
-		new HttpSessionCsrfTokenRepository().saveToken(csrfToken, request, response);
-		request.setParameter(csrfToken.getParameterName(), csrfToken.getToken());
-
-		this.spring.getContext().getBean("springSecurityFilterChain", Filter.class).doFilter(request, response,
-				new MockFilterChain());
-		assertThat(response.getRedirectedUrl()).isEqualTo("/login?logout");
-	}
-
 	@EnableWebSecurity
 	static class DefaultFiltersConfigPermitAll extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java
index 43e409ec30..d2110741cf 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java
@@ -176,31 +176,6 @@ public class DefaultLoginPageConfigurerTests {
 						+ "      \n" + "\n" + ""));
 	}
 
-	@EnableWebSecurity
-	static class DefaultLoginPageConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.formLogin();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginPageWhenLoggedOutAndCustomLogoutSuccessHandlerThenDoesNotRenderLoginPage() throws Exception {
 		this.spring.register(DefaultLoginPageCustomLogoutSuccessHandlerConfig.class).autowire();
@@ -208,25 +183,6 @@ public class DefaultLoginPageConfigurerTests {
 		this.mvc.perform(get("/login?logout")).andExpect(content().string(""));
 	}
 
-	@EnableWebSecurity
-	static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.logout()
-					.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
-					.and()
-				.formLogin();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginPageWhenLoggedOutAndCustomLogoutSuccessUrlThenDoesNotRenderLoginPage() throws Exception {
 		this.spring.register(DefaultLoginPageCustomLogoutSuccessUrlConfig.class).autowire();
@@ -234,25 +190,6 @@ public class DefaultLoginPageConfigurerTests {
 		this.mvc.perform(get("/login?logout")).andExpect(content().string(""));
 	}
 
-	@EnableWebSecurity
-	static class DefaultLoginPageCustomLogoutSuccessUrlConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.logout()
-					.logoutSuccessUrl("/login?logout")
-					.and()
-				.formLogin();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginPageWhenRememberConfigureThenDefaultLoginPageWithRememberMeCheckbox() throws Exception {
 		this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire();
@@ -283,24 +220,6 @@ public class DefaultLoginPageConfigurerTests {
 						+ "      \n" + "\n" + ""));
 	}
 
-	@EnableWebSecurity
-	static class DefaultLoginPageWithRememberMeConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.formLogin()
-					.and()
-				.rememberMe();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginPageWhenOpenIdLoginConfiguredThenOpedIdLoginPage() throws Exception {
 		this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire();
@@ -327,22 +246,6 @@ public class DefaultLoginPageConfigurerTests {
 						+ "      \n" + "\n" + ""));
 	}
 
-	@EnableWebSecurity
-	static class DefaultLoginPageWithOpenIDConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.openidLogin();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginPageWhenOpenIdLoginAndFormLoginAndRememberMeConfiguredThenOpedIdLoginPage() throws Exception {
 		this.spring.register(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig.class).autowire();
@@ -383,55 +286,6 @@ public class DefaultLoginPageConfigurerTests {
 						+ "      \n" + "\n" + ""));
 	}
 
-	@EnableWebSecurity
-	static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.rememberMe()
-					.and()
-				.formLogin()
-					.and()
-				.openidLogin();
-			// @formatter:on
-		}
-
-	}
-
-	@Test
-	public void configureWhenAuthenticationEntryPointThenNoDefaultLoginPageGeneratingFilter() {
-		this.spring.register(DefaultLoginWithCustomAuthenticationEntryPointConfig.class).autowire();
-
-		FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
-		assertThat(filterChain.getFilterChains().get(0).getFilters().stream()
-				.filter(filter -> filter.getClass().isAssignableFrom(DefaultLoginPageGeneratingFilter.class)).count())
-						.isZero();
-	}
-
-	@EnableWebSecurity
-	static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.exceptionHandling()
-					.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
-					.and()
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.formLogin();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnDefaultLoginPageGeneratingFilter() {
 		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@@ -465,6 +319,152 @@ public class DefaultLoginPageConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
 	}
 
+	@Test
+	public void configureWhenAuthenticationEntryPointThenNoDefaultLoginPageGeneratingFilter() {
+		this.spring.register(DefaultLoginWithCustomAuthenticationEntryPointConfig.class).autowire();
+
+		FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
+		assertThat(filterChain.getFilterChains().get(0).getFilters().stream()
+				.filter(filter -> filter.getClass().isAssignableFrom(DefaultLoginPageGeneratingFilter.class)).count())
+						.isZero();
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginPageConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.formLogin();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.logout()
+					.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
+					.and()
+				.formLogin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginPageCustomLogoutSuccessUrlConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.logout()
+					.logoutSuccessUrl("/login?logout")
+					.and()
+				.formLogin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginPageWithRememberMeConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.formLogin()
+					.and()
+				.rememberMe();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginPageWithOpenIDConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.openidLogin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.rememberMe()
+					.and()
+				.formLogin()
+					.and()
+				.openidLogin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.exceptionHandling()
+					.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
+					.and()
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.formLogin();
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
index ab6021c5c0..4bfc897690 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
@@ -60,6 +60,26 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
 		this.mvc.perform(get("/goodbye")).andExpect(status().isForbidden());
 	}
 
+	@Test
+	@WithMockUser(roles = "ANYTHING")
+	public void getWhenAccessDeniedOverriddenInLambdaThenCustomizesResponseByRequest() throws Exception {
+		this.spring.register(RequestMatcherBasedAccessDeniedHandlerInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
+
+		this.mvc.perform(get("/goodbye")).andExpect(status().isForbidden());
+	}
+
+	@Test
+	@WithMockUser(roles = "ANYTHING")
+	public void getWhenAccessDeniedOverriddenByOnlyOneHandlerThenAllRequestsUseThatHandler() throws Exception {
+		this.spring.register(SingleRequestMatcherAccessDeniedHandlerConfig.class).autowire();
+
+		this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
+
+		this.mvc.perform(get("/goodbye")).andExpect(status().isIAmATeapot());
+	}
+
 	@EnableWebSecurity
 	static class RequestMatcherBasedAccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
 
@@ -85,16 +105,6 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
 
 	}
 
-	@Test
-	@WithMockUser(roles = "ANYTHING")
-	public void getWhenAccessDeniedOverriddenInLambdaThenCustomizesResponseByRequest() throws Exception {
-		this.spring.register(RequestMatcherBasedAccessDeniedHandlerInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
-
-		this.mvc.perform(get("/goodbye")).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class RequestMatcherBasedAccessDeniedHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -125,16 +135,6 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
 
 	}
 
-	@Test
-	@WithMockUser(roles = "ANYTHING")
-	public void getWhenAccessDeniedOverriddenByOnlyOneHandlerThenAllRequestsUseThatHandler() throws Exception {
-		this.spring.register(SingleRequestMatcherAccessDeniedHandlerConfig.class).autowire();
-
-		this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
-
-		this.mvc.perform(get("/goodbye")).andExpect(status().isIAmATeapot());
-	}
-
 	@EnableWebSecurity
 	static class SingleRequestMatcherAccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java
index 54b341f14f..3728529db4 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java
@@ -70,35 +70,6 @@ public class ExceptionHandlingConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
 	}
 
-	@EnableWebSecurity
-	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
-
-		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.exceptionHandling();
-			// @formatter:on
-		}
-
-		@Bean
-		static ObjectPostProcessor objectPostProcessor() {
-			return objectPostProcessor;
-		}
-
-	}
-
-	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
-
-		@Override
-		public  O postProcess(O object) {
-			return object;
-		}
-
-	}
-
 	// SEC-2199
 	@Test
 	public void getWhenAcceptHeaderIsApplicationXhtmlXmlThenRespondsWith302() throws Exception {
@@ -226,6 +197,71 @@ public class ExceptionHandlingConfigurerTests {
 				.andExpect(status().isUnauthorized());
 	}
 
+	@Test
+	public void getWhenCustomContentNegotiationStrategyThenStrategyIsUsed() throws Exception {
+		this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class, DefaultSecurityConfig.class)
+				.autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(OverrideContentNegotiationStrategySharedObjectConfig.CNS, atLeastOnce())
+				.resolveMediaTypes(any(NativeWebRequest.class));
+	}
+
+	@Test
+	public void getWhenUsingDefaultsAndUnauthenticatedThenRedirectsToLogin() throws Exception {
+		this.spring.register(DefaultHttpConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type"))
+				.andExpect(redirectedUrl("http://localhost/login"));
+	}
+
+	@Test
+	public void getWhenDeclaringHttpBasicBeforeFormLoginThenRespondsWith401() throws Exception {
+		this.spring.register(BasicAuthenticationEntryPointBeforeFormLoginConfig.class).autowire();
+
+		this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type")).andExpect(status().isUnauthorized());
+	}
+
+	@Test
+	public void getWhenInvokingExceptionHandlingTwiceThenOriginalEntryPointUsed() throws Exception {
+		this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(InvokeTwiceDoesNotOverrideConfig.AEP).commence(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any(AuthenticationException.class));
+	}
+
+	@EnableWebSecurity
+	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
+
+		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.exceptionHandling();
+			// @formatter:on
+		}
+
+		@Bean
+		static ObjectPostProcessor objectPostProcessor() {
+			return objectPostProcessor;
+		}
+
+	}
+
+	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
+
+		@Override
+		public  O postProcess(O object) {
+			return object;
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class DefaultSecurityConfig {
 
@@ -267,17 +303,6 @@ public class ExceptionHandlingConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCustomContentNegotiationStrategyThenStrategyIsUsed() throws Exception {
-		this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class, DefaultSecurityConfig.class)
-				.autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(OverrideContentNegotiationStrategySharedObjectConfig.CNS, atLeastOnce())
-				.resolveMediaTypes(any(NativeWebRequest.class));
-	}
-
 	@EnableWebSecurity
 	static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
 
@@ -290,26 +315,11 @@ public class ExceptionHandlingConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenUsingDefaultsAndUnauthenticatedThenRedirectsToLogin() throws Exception {
-		this.spring.register(DefaultHttpConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type"))
-				.andExpect(redirectedUrl("http://localhost/login"));
-	}
-
 	@EnableWebSecurity
 	static class DefaultHttpConfig extends WebSecurityConfigurerAdapter {
 
 	}
 
-	@Test
-	public void getWhenDeclaringHttpBasicBeforeFormLoginThenRespondsWith401() throws Exception {
-		this.spring.register(BasicAuthenticationEntryPointBeforeFormLoginConfig.class).autowire();
-
-		this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type")).andExpect(status().isUnauthorized());
-	}
-
 	@EnableWebSecurity
 	static class BasicAuthenticationEntryPointBeforeFormLoginConfig extends WebSecurityConfigurerAdapter {
 
@@ -328,16 +338,6 @@ public class ExceptionHandlingConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenInvokingExceptionHandlingTwiceThenOriginalEntryPointUsed() throws Exception {
-		this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(InvokeTwiceDoesNotOverrideConfig.AEP).commence(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any(AuthenticationException.class));
-	}
-
 	@EnableWebSecurity
 	static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java
index 1ce457ff8b..dcb870439c 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java
@@ -90,20 +90,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 						"role should not start with 'ROLE_' since it is automatically inserted. Got 'ROLE_USER'");
 	}
 
-	@EnableWebSecurity
-	static class HasRoleStartingWithRoleConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("ROLE_USER");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenNoCustomAccessDecisionManagerThenUsesAffirmativeBased() {
 		this.spring.register(NoSpecificAccessDecisionManagerConfig.class).autowire();
@@ -111,27 +97,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		verify(NoSpecificAccessDecisionManagerConfig.objectPostProcessor).postProcess(any(AffirmativeBased.class));
 	}
 
-	@EnableWebSecurity
-	static class NoSpecificAccessDecisionManagerConfig extends WebSecurityConfigurerAdapter {
-
-		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER");
-			// @formatter:on
-		}
-
-		@Bean
-		static ObjectPostProcessor objectPostProcessor() {
-			return objectPostProcessor;
-		}
-
-	}
-
 	@Test
 	public void configureWhenAuthorizedRequestsAndNoRequestsThenException() {
 		assertThatThrownBy(() -> this.spring.register(NoRequestsConfig.class).autowire())
@@ -139,40 +104,12 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 						"At least one mapping is required (i.e. authorizeRequests().anyRequest().authenticated())");
 	}
 
-	@EnableWebSecurity
-	static class NoRequestsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenAnyRequestIncompleteMappingThenException() {
 		assertThatThrownBy(() -> this.spring.register(IncompleteMappingConfig.class).autowire())
 				.isInstanceOf(BeanCreationException.class).hasMessageContaining("An incomplete mapping was found for ");
 	}
 
-	@EnableWebSecurity
-	static class IncompleteMappingConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.antMatchers("/a").authenticated()
-					.anyRequest();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
 		this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire();
@@ -197,22 +134,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
 	}
 
-	@EnableWebSecurity
-	static class RoleUserAnyAuthorityConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.authorizeRequests()
-					.anyRequest().hasAnyAuthority("ROLE_USER");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
 		this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire();
@@ -237,22 +158,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
 	}
 
-	@EnableWebSecurity
-	static class RoleUserAuthorityConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.authorizeRequests()
-					.anyRequest().hasAuthority("ROLE_USER");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
 		this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire();
@@ -285,22 +190,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
 	}
 
-	@EnableWebSecurity
-	static class RoleUserOrRoleAdminAuthorityConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.authorizeRequests()
-					.anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHasAnyRoleUserConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
 		this.spring.register(RoleUserConfig.class, BasicController.class).autowire();
@@ -315,20 +204,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		this.mvc.perform(get("/").with(user("user").roles("ADMIN"))).andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class RoleUserConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasAnyRole("USER");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenRoleUserOrAdminConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
 		this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire();
@@ -350,20 +225,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		this.mvc.perform(get("/").with(user("user").roles("OTHER"))).andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class RoleUserOrAdminConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasAnyRole("USER", "ADMIN");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHasIpAddressConfiguredAndIpAddressMatchesThenRespondsWithOk() throws Exception {
 		this.spring.register(HasIpAddressConfig.class, BasicController.class).autowire();
@@ -384,22 +245,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		})).andExpect(status().isUnauthorized());
 	}
 
-	@EnableWebSecurity
-	static class HasIpAddressConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.authorizeRequests()
-					.anyRequest().hasIpAddress("192.168.1.0");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenAnonymousConfiguredAndAnonymousUserThenRespondsWithOk() throws Exception {
 		this.spring.register(AnonymousConfig.class, BasicController.class).autowire();
@@ -414,22 +259,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 		this.mvc.perform(get("/").with(user("user"))).andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class AnonymousConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.authorizeRequests()
-					.anyRequest().anonymous();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenRememberMeConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception {
 		this.spring.register(RememberMeConfig.class, BasicController.class).autowire();
@@ -446,6 +275,377 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 				.andExpect(status().isOk());
 	}
 
+	@Test
+	public void getWhenDenyAllConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception {
+		this.spring.register(DenyAllConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
+	}
+
+	@Test
+	public void getWheDenyAllConfiguredAndUserLoggedInThenRespondsWithForbidden() throws Exception {
+		this.spring.register(DenyAllConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void getWhenNotDenyAllConfiguredAndNoUserThenRespondsWithOk() throws Exception {
+		this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenNotDenyAllConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
+		this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/").with(authentication(
+				new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
+				.andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception {
+		this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/").with(authentication(
+				new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
+				.andExpect(status().isUnauthorized());
+	}
+
+	@Test
+	public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception {
+		this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithOk() throws Exception {
+		this.spring.register(AccessConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isOk());
+	}
+
+	@Test
+	public void postWhenAccessRoleUserOrGetRequestConfiguredAndRoleUserThenRespondsWithOk() throws Exception {
+		this.spring.register(AccessConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(post("/").with(csrf()).with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void postWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithUnauthorized() throws Exception {
+		this.spring.register(AccessConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(post("/").with(csrf())).andExpect(status().isUnauthorized());
+	}
+
+	@Test
+	public void authorizeRequestsWhenInvokedTwiceThenUsesOriginalConfiguration() throws Exception {
+		this.spring.register(InvokeTwiceDoesNotResetConfig.class, BasicController.class).autowire();
+
+		this.mvc.perform(post("/").with(csrf())).andExpect(status().isUnauthorized());
+	}
+
+	@Test
+	public void configureWhenUsingAllAuthorizeRequestPropertiesThenCompiles() {
+		this.spring.register(AllPropertiesWorkConfig.class).autowire();
+	}
+
+	@Test
+	public void configureWhenRegisteringObjectPostProcessorThenApplicationListenerInvokedOnAuthorizedEvent()
+			throws Exception {
+		this.spring.register(AuthorizedRequestsWithPostProcessorConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(AuthorizedRequestsWithPostProcessorConfig.AL).onApplicationEvent(any(AuthorizedEvent.class));
+	}
+
+	@Test
+	public void getWhenPermissionCheckAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
+		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/admin").with(user("user").roles("USER"))).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void getWhenPermissionCheckAndRoleMatchesThenRespondsWithOk() throws Exception {
+		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/user").with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenPermissionCheckAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
+		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenPermissionCheckAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() throws Exception {
+		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void getWhenCustomExpressionHandlerAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
+		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/admin").with(user("user").roles("USER"))).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void getWhenCustomExpressionHandlerAndRoleMatchesThenRespondsWithOk() throws Exception {
+		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/user").with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenCustomExpressionHandlerAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
+		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenCustomExpressionHandlerAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden()
+			throws Exception {
+		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
+	}
+
+	// SEC-3011
+	@Test
+	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnAccessDecisionManager() {
+		this.spring.register(Sec3011Config.class).autowire();
+
+		verify(Sec3011Config.objectPostProcessor).postProcess(any(AccessDecisionManager.class));
+	}
+
+	@Test
+	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithIdAndTypeMatchesThenRespondsWithOk()
+			throws Exception {
+		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/allow")).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithIdAndTypeDoesNotMatchThenRespondsWithForbidden()
+			throws Exception {
+		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/deny")).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithObjectMatchesThenRespondsWithOk()
+			throws Exception {
+		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/allowObject")).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithObjectDoesNotMatchThenRespondsWithForbidden()
+			throws Exception {
+		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/denyObject")).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void getWhenRegisteringRoleHierarchyAndRelatedRoleAllowedThenRespondsWithOk() throws Exception {
+		this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
+	}
+
+	@Test
+	public void getWhenRegisteringRoleHierarchyAndNoRelatedRolesAllowedThenRespondsWithForbidden() throws Exception {
+		this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire();
+
+		this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
+	}
+
+	@EnableWebSecurity
+	static class HasRoleStartingWithRoleConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("ROLE_USER");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NoSpecificAccessDecisionManagerConfig extends WebSecurityConfigurerAdapter {
+
+		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER");
+			// @formatter:on
+		}
+
+		@Bean
+		static ObjectPostProcessor objectPostProcessor() {
+			return objectPostProcessor;
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NoRequestsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class IncompleteMappingConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.antMatchers("/a").authenticated()
+					.anyRequest();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RoleUserAnyAuthorityConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.authorizeRequests()
+					.anyRequest().hasAnyAuthority("ROLE_USER");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RoleUserAuthorityConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.authorizeRequests()
+					.anyRequest().hasAuthority("ROLE_USER");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RoleUserOrRoleAdminAuthorityConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.authorizeRequests()
+					.anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RoleUserConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasAnyRole("USER");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RoleUserOrAdminConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasAnyRole("USER", "ADMIN");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HasIpAddressConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.authorizeRequests()
+					.anyRequest().hasIpAddress("192.168.1.0");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class AnonymousConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.authorizeRequests()
+					.anyRequest().anonymous();
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class RememberMeConfig extends WebSecurityConfigurerAdapter {
 
@@ -473,20 +673,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenDenyAllConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception {
-		this.spring.register(DenyAllConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	public void getWheDenyAllConfiguredAndUserLoggedInThenRespondsWithForbidden() throws Exception {
-		this.spring.register(DenyAllConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class DenyAllConfig extends WebSecurityConfigurerAdapter {
 
@@ -503,22 +689,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenNotDenyAllConfiguredAndNoUserThenRespondsWithOk() throws Exception {
-		this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenNotDenyAllConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
-		this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/").with(authentication(
-				new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
-				.andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class NotDenyAllConfig extends WebSecurityConfigurerAdapter {
 
@@ -535,22 +705,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception {
-		this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/").with(authentication(
-				new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
-				.andExpect(status().isUnauthorized());
-	}
-
-	@Test
-	public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception {
-		this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class FullyAuthenticatedConfig extends WebSecurityConfigurerAdapter {
 
@@ -569,27 +723,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithOk() throws Exception {
-		this.spring.register(AccessConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isOk());
-	}
-
-	@Test
-	public void postWhenAccessRoleUserOrGetRequestConfiguredAndRoleUserThenRespondsWithOk() throws Exception {
-		this.spring.register(AccessConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(post("/").with(csrf()).with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
-	@Test
-	public void postWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithUnauthorized() throws Exception {
-		this.spring.register(AccessConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(post("/").with(csrf())).andExpect(status().isUnauthorized());
-	}
-
 	@EnableWebSecurity
 	static class AccessConfig extends WebSecurityConfigurerAdapter {
 
@@ -608,13 +741,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void authorizeRequestsWhenInvokedTwiceThenUsesOriginalConfiguration() throws Exception {
-		this.spring.register(InvokeTwiceDoesNotResetConfig.class, BasicController.class).autowire();
-
-		this.mvc.perform(post("/").with(csrf())).andExpect(status().isUnauthorized());
-	}
-
 	@EnableWebSecurity
 	static class InvokeTwiceDoesNotResetConfig extends WebSecurityConfigurerAdapter {
 
@@ -633,11 +759,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenUsingAllAuthorizeRequestPropertiesThenCompiles() {
-		this.spring.register(AllPropertiesWorkConfig.class).autowire();
-	}
-
 	@EnableWebSecurity
 	static class AllPropertiesWorkConfig extends WebSecurityConfigurerAdapter {
 
@@ -661,16 +782,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenRegisteringObjectPostProcessorThenApplicationListenerInvokedOnAuthorizedEvent()
-			throws Exception {
-		this.spring.register(AuthorizedRequestsWithPostProcessorConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(AuthorizedRequestsWithPostProcessorConfig.AL).onApplicationEvent(any(AuthorizedEvent.class));
-	}
-
 	@EnableWebSecurity
 	static class AuthorizedRequestsWithPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -700,34 +811,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenPermissionCheckAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
-		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/admin").with(user("user").roles("USER"))).andExpect(status().isForbidden());
-	}
-
-	@Test
-	public void getWhenPermissionCheckAndRoleMatchesThenRespondsWithOk() throws Exception {
-		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/user").with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenPermissionCheckAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
-		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenPermissionCheckAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() throws Exception {
-		this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class UseBeansInExpressions extends WebSecurityConfigurerAdapter {
 
@@ -758,35 +841,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCustomExpressionHandlerAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
-		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/admin").with(user("user").roles("USER"))).andExpect(status().isForbidden());
-	}
-
-	@Test
-	public void getWhenCustomExpressionHandlerAndRoleMatchesThenRespondsWithOk() throws Exception {
-		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/user").with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenCustomExpressionHandlerAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
-		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenCustomExpressionHandlerAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden()
-			throws Exception {
-		this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class CustomExpressionRootConfig extends WebSecurityConfigurerAdapter {
 
@@ -837,14 +891,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	// SEC-3011
-	@Test
-	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnAccessDecisionManager() {
-		this.spring.register(Sec3011Config.class).autowire();
-
-		verify(Sec3011Config.objectPostProcessor).postProcess(any(AccessDecisionManager.class));
-	}
-
 	@EnableWebSecurity
 	static class Sec3011Config extends WebSecurityConfigurerAdapter {
 
@@ -874,38 +920,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithIdAndTypeMatchesThenRespondsWithOk()
-			throws Exception {
-		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/allow")).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithIdAndTypeDoesNotMatchThenRespondsWithForbidden()
-			throws Exception {
-		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/deny")).andExpect(status().isForbidden());
-	}
-
-	@Test
-	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithObjectMatchesThenRespondsWithOk()
-			throws Exception {
-		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/allowObject")).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenRegisteringPermissionEvaluatorAndPermissionWithObjectDoesNotMatchThenRespondsWithForbidden()
-			throws Exception {
-		this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/denyObject")).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class PermissionEvaluatorConfig extends WebSecurityConfigurerAdapter {
 
@@ -941,20 +955,6 @@ public class ExpressionUrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenRegisteringRoleHierarchyAndRelatedRoleAllowedThenRespondsWithOk() throws Exception {
-		this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
-	}
-
-	@Test
-	public void getWhenRegisteringRoleHierarchyAndNoRelatedRolesAllowedThenRespondsWithForbidden() throws Exception {
-		this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire();
-
-		this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class RoleHierarchyConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
index 7d3592b5a5..d3aff8f656 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
@@ -77,23 +77,6 @@ public class FormLoginConfigurerTests {
 		verify(config.requestCache).getRequest(any(), any());
 	}
 
-	@EnableWebSecurity
-	static class RequestCacheConfig extends WebSecurityConfigurerAdapter {
-
-		private RequestCache requestCache = mock(RequestCache.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.formLogin().and()
-				.requestCache()
-					.requestCache(this.requestCache);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestCacheAsBean() throws Exception {
 		this.spring.register(RequestCacheBeanConfig.class, AuthenticationTestConfiguration.class).autowire();
@@ -105,16 +88,6 @@ public class FormLoginConfigurerTests {
 		verify(requestCache).getRequest(any(), any());
 	}
 
-	@EnableWebSecurity
-	static class RequestCacheBeanConfig {
-
-		@Bean
-		RequestCache requestCache() {
-			return mock(RequestCache.class);
-		}
-
-	}
-
 	@Test
 	public void loginWhenFormLoginConfiguredThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
 		this.spring.register(FormLoginConfig.class).autowire();
@@ -160,41 +133,6 @@ public class FormLoginConfigurerTests {
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
-	@EnableWebSecurity
-	static class FormLoginConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		public void configure(WebSecurity web) {
-			// @formatter:off
-			web
-				.ignoring()
-					.antMatchers("/resources/**");
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.formLogin()
-					.loginPage("/login");
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
 		this.spring.register(FormLoginInLambdaConfig.class).autowire();
@@ -240,32 +178,6 @@ public class FormLoginConfigurerTests {
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
-	@EnableWebSecurity
-	static class FormLoginInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests(authorizeRequests ->
-					authorizeRequests
-						.anyRequest().hasRole("USER")
-				)
-				.formLogin(withDefaults());
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
 		this.spring.register(FormLoginConfigPermitAll.class).autowire();
@@ -288,23 +200,6 @@ public class FormLoginConfigurerTests {
 				.andExpect(redirectedUrl("/login?error"));
 	}
 
-	@EnableWebSecurity
-	static class FormLoginConfigPermitAll extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.formLogin()
-					.permitAll();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getLoginPageWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
 		this.spring.register(FormLoginDefaultsConfig.class).autowire();
@@ -341,6 +236,198 @@ public class FormLoginConfigurerTests {
 		this.mockMvc.perform(get("/authenticate?logout")).andExpect(redirectedUrl(null));
 	}
 
+	@Test
+	public void getLoginPageWhenCustomLoginPageInLambdaThenPermittedAndNoRedirect() throws Exception {
+		this.spring.register(FormLoginDefaultsInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(get("/authenticate")).andExpect(redirectedUrl(null));
+	}
+
+	@Test
+	public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
+		this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin("/loginCheck")).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
+	}
+
+	@Test
+	public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
+		this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin("/loginCheck")).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
+	}
+
+	@Test
+	public void requestWhenCustomPortMapperThenPortMapperUsed() throws Exception {
+		FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
+		when(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).thenReturn(9443);
+		this.spring.register(FormLoginUsesPortMapperConfig.class).autowire();
+
+		this.mockMvc.perform(get("http://localhost:9090")).andExpect(status().isFound())
+				.andExpect(redirectedUrl("https://localhost:9443/login"));
+
+		verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any());
+	}
+
+	@Test
+	public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception {
+		this.spring.register(PermitAllIgnoresFailureHandlerConfig.class).autowire();
+
+		this.mockMvc.perform(get("/login?error")).andExpect(status().isFound())
+				.andExpect(redirectedUrl("http://localhost/login"));
+	}
+
+	@Test
+	public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception {
+		this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin().user("custom-username", "user")).andExpect(authenticated());
+	}
+
+	@Test
+	public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception {
+		this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin().user("invalid")).andExpect(forwardedUrl("/failure_forward_url"));
+	}
+
+	@Test
+	public void loginWhenSuccessForwardUrlThenForwardsToSuccessForwardUrl() throws Exception {
+		this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin()).andExpect(forwardedUrl("/success_forward_url"));
+	}
+
+	@Test
+	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() {
+		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+		this.spring.register(ObjectPostProcessorConfig.class).autowire();
+
+		verify(ObjectPostProcessorConfig.objectPostProcessor)
+				.postProcess(any(UsernamePasswordAuthenticationFilter.class));
+	}
+
+	@Test
+	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() {
+		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+		this.spring.register(ObjectPostProcessorConfig.class).autowire();
+
+		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(LoginUrlAuthenticationEntryPoint.class));
+	}
+
+	@Test
+	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
+		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+		this.spring.register(ObjectPostProcessorConfig.class).autowire();
+
+		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
+	}
+
+	@EnableWebSecurity
+	static class RequestCacheConfig extends WebSecurityConfigurerAdapter {
+
+		private RequestCache requestCache = mock(RequestCache.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin().and()
+				.requestCache()
+					.requestCache(this.requestCache);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RequestCacheBeanConfig {
+
+		@Bean
+		RequestCache requestCache() {
+			return mock(RequestCache.class);
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class FormLoginConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		public void configure(WebSecurity web) {
+			// @formatter:off
+			web
+				.ignoring()
+					.antMatchers("/resources/**");
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.formLogin()
+					.loginPage("/login");
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class FormLoginInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.formLogin(withDefaults());
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class FormLoginConfigPermitAll extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.formLogin()
+					.permitAll();
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class FormLoginDefaultsConfig extends WebSecurityConfigurerAdapter {
 
@@ -362,13 +449,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void getLoginPageWhenCustomLoginPageInLambdaThenPermittedAndNoRedirect() throws Exception {
-		this.spring.register(FormLoginDefaultsInLambdaConfig.class).autowire();
-
-		this.mockMvc.perform(get("/authenticate")).andExpect(redirectedUrl(null));
-	}
-
 	@EnableWebSecurity
 	static class FormLoginDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -391,13 +471,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
-		this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin("/loginCheck")).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
-	}
-
 	@EnableWebSecurity
 	static class FormLoginLoginProcessingUrlConfig extends WebSecurityConfigurerAdapter {
 
@@ -434,13 +507,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
-		this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin("/loginCheck")).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
-	}
-
 	@EnableWebSecurity
 	static class FormLoginLoginProcessingUrlInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -479,18 +545,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenCustomPortMapperThenPortMapperUsed() throws Exception {
-		FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
-		when(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).thenReturn(9443);
-		this.spring.register(FormLoginUsesPortMapperConfig.class).autowire();
-
-		this.mockMvc.perform(get("http://localhost:9090")).andExpect(status().isFound())
-				.andExpect(redirectedUrl("https://localhost:9443/login"));
-
-		verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any());
-	}
-
 	@EnableWebSecurity
 	static class FormLoginUsesPortMapperConfig extends WebSecurityConfigurerAdapter {
 
@@ -516,14 +570,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception {
-		this.spring.register(PermitAllIgnoresFailureHandlerConfig.class).autowire();
-
-		this.mockMvc.perform(get("/login?error")).andExpect(status().isFound())
-				.andExpect(redirectedUrl("http://localhost/login"));
-	}
-
 	@EnableWebSecurity
 	static class PermitAllIgnoresFailureHandlerConfig extends WebSecurityConfigurerAdapter {
 
@@ -544,13 +590,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception {
-		this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin().user("custom-username", "user")).andExpect(authenticated());
-	}
-
 	@EnableWebSecurity
 	static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
@@ -576,20 +615,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception {
-		this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin().user("invalid")).andExpect(forwardedUrl("/failure_forward_url"));
-	}
-
-	@Test
-	public void loginWhenSuccessForwardUrlThenForwardsToSuccessForwardUrl() throws Exception {
-		this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
-
-		this.mockMvc.perform(formLogin()).andExpect(forwardedUrl("/success_forward_url"));
-	}
-
 	@EnableWebSecurity
 	static class FormLoginUserForwardAuthenticationSuccessAndFailureConfig extends WebSecurityConfigurerAdapter {
 
@@ -620,31 +645,6 @@ public class FormLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() {
-		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-		this.spring.register(ObjectPostProcessorConfig.class).autowire();
-
-		verify(ObjectPostProcessorConfig.objectPostProcessor)
-				.postProcess(any(UsernamePasswordAuthenticationFilter.class));
-	}
-
-	@Test
-	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() {
-		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-		this.spring.register(ObjectPostProcessorConfig.class).autowire();
-
-		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(LoginUrlAuthenticationEntryPoint.class));
-	}
-
-	@Test
-	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
-		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-		this.spring.register(ObjectPostProcessorConfig.class).autowire();
-
-		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
-	}
-
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java
index 908c61fecd..0586a75bac 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java
@@ -47,6 +47,18 @@ public class HeadersConfigurerEagerHeadersTests {
 	@Autowired
 	MockMvc mvc;
 
+	@Test
+	public void requestWhenHeadersEagerlyConfiguredThenHeadersAreWritten() throws Exception {
+		this.spring.register(HeadersAtTheBeginningOfRequestConfig.class).autowire();
+
+		this.mvc.perform(get("/").secure(true)).andExpect(header().string("X-Content-Type-Options", "nosniff"))
+				.andExpect(header().string("X-Frame-Options", "DENY"))
+				.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
+				.andExpect(header().string(CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
+				.andExpect(header().string(EXPIRES, "0")).andExpect(header().string(PRAGMA, "no-cache"))
+				.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
+	}
+
 	@EnableWebSecurity
 	public static class HeadersAtTheBeginningOfRequestConfig extends WebSecurityConfigurerAdapter {
 
@@ -65,16 +77,4 @@ public class HeadersConfigurerEagerHeadersTests {
 
 	}
 
-	@Test
-	public void requestWhenHeadersEagerlyConfiguredThenHeadersAreWritten() throws Exception {
-		this.spring.register(HeadersAtTheBeginningOfRequestConfig.class).autowire();
-
-		this.mvc.perform(get("/").secure(true)).andExpect(header().string("X-Content-Type-Options", "nosniff"))
-				.andExpect(header().string("X-Frame-Options", "DENY"))
-				.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
-				.andExpect(header().string(CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
-				.andExpect(header().string(EXPIRES, "0")).andExpect(header().string(PRAGMA, "no-cache"))
-				.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
index b5e0df70fe..275f89c498 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
@@ -77,19 +77,6 @@ public class HeadersConfigurerTests {
 				HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
 	}
 
-	@EnableWebSecurity
-	static class HeadersConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeadersConfiguredInLambdaThenDefaultHeadersInResponse() throws Exception {
 		this.spring.register(HeadersInLambdaConfig.class).autowire();
@@ -108,19 +95,6 @@ public class HeadersConfigurerTests {
 				HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
 	}
 
-	@EnableWebSecurity
-	static class HeadersInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers(withDefaults());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeaderDefaultsDisabledAndContentTypeConfiguredThenOnlyContentTypeHeaderInResponse()
 			throws Exception {
@@ -131,21 +105,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_CONTENT_TYPE_OPTIONS);
 	}
 
-	@EnableWebSecurity
-	static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.contentTypeOptions();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenOnlyContentTypeConfiguredInLambdaThenOnlyContentTypeHeaderInResponse() throws Exception {
 		this.spring.register(ContentTypeOptionsInLambdaConfig.class).autowire();
@@ -155,23 +114,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_CONTENT_TYPE_OPTIONS);
 	}
 
-	@EnableWebSecurity
-	static class ContentTypeOptionsInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers(headers ->
-					headers
-						.defaultsDisabled()
-						.contentTypeOptions(withDefaults())
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeaderDefaultsDisabledAndFrameOptionsConfiguredThenOnlyFrameOptionsHeaderInResponse()
 			throws Exception {
@@ -182,21 +124,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_FRAME_OPTIONS);
 	}
 
-	@EnableWebSecurity
-	static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.frameOptions();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeaderDefaultsDisabledAndHstsConfiguredThenOnlyStrictTransportSecurityHeaderInResponse()
 			throws Exception {
@@ -209,21 +136,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
 	}
 
-	@EnableWebSecurity
-	static class HstsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.httpStrictTransportSecurity();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeaderDefaultsDisabledAndCacheControlConfiguredThenCacheControlAndExpiresAndPragmaHeadersInResponse()
 			throws Exception {
@@ -237,21 +149,6 @@ public class HeadersConfigurerTests {
 				HttpHeaders.EXPIRES, HttpHeaders.PRAGMA);
 	}
 
-	@EnableWebSecurity
-	static class CacheControlConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.cacheControl();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenOnlyCacheControlConfiguredInLambdaThenCacheControlAndExpiresAndPragmaHeadersInResponse()
 			throws Exception {
@@ -265,23 +162,6 @@ public class HeadersConfigurerTests {
 				HttpHeaders.EXPIRES, HttpHeaders.PRAGMA);
 	}
 
-	@EnableWebSecurity
-	static class CacheControlInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers(headers ->
-					headers
-						.defaultsDisabled()
-						.cacheControl(withDefaults())
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredThenOnlyXssProtectionHeaderInResponse()
 			throws Exception {
@@ -292,21 +172,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
 	}
 
-	@EnableWebSecurity
-	static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.xssProtection();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenOnlyXssProtectionConfiguredInLambdaThenOnlyXssProtectionHeaderInResponse() throws Exception {
 		this.spring.register(XssProtectionInLambdaConfig.class).autowire();
@@ -316,23 +181,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
 	}
 
-	@EnableWebSecurity
-	static class XssProtectionInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers(headers ->
-					headers
-						.defaultsDisabled()
-						.xssProtection(withDefaults())
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenFrameOptionsSameOriginConfiguredThenFrameOptionsHeaderHasValueSameOrigin() throws Exception {
 		this.spring.register(HeadersCustomSameOriginConfig.class).autowire();
@@ -342,20 +190,6 @@ public class HeadersConfigurerTests {
 				.andReturn();
 	}
 
-	@EnableWebSecurity
-	static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.frameOptions().sameOrigin();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenFrameOptionsSameOriginConfiguredInLambdaThenFrameOptionsHeaderHasValueSameOrigin()
 			throws Exception {
@@ -366,22 +200,6 @@ public class HeadersConfigurerTests {
 				.andReturn();
 	}
 
-	@EnableWebSecurity
-	static class HeadersCustomSameOriginInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers(headers ->
-					headers
-						.frameOptions(frameOptionsConfig -> frameOptionsConfig.sameOrigin())
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenHeaderDefaultsDisabledAndPublicHpkpWithNoPinThenNoHeadersInResponse() throws Exception {
 		this.spring.register(HpkpConfigNoPins.class).autowire();
@@ -390,21 +208,6 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).isEmpty();
 	}
 
-	@EnableWebSecurity
-	static class HpkpConfigNoPins extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.httpPublicKeyPinning();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenSecureRequestAndHpkpWithPinThenPublicKeyPinsReportOnlyHeaderInResponse() throws Exception {
 		this.spring.register(HpkpConfig.class).autowire();
@@ -424,6 +227,414 @@ public class HeadersConfigurerTests {
 		assertThat(mvcResult.getResponse().getHeaderNames()).isEmpty();
 	}
 
+	@Test
+	public void getWhenHpkpWithMultiplePinsThenPublicKeyPinsReportOnlyHeaderWithMultiplePinsInResponse()
+			throws Exception {
+		this.spring.register(HpkpConfigWithPins.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
+				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenHpkpWithCustomAgeThenPublicKeyPinsReportOnlyHeaderWithCustomAgeInResponse() throws Exception {
+		this.spring.register(HpkpConfigCustomAge.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+						"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenHpkpWithReportOnlyFalseThenPublicKeyPinsHeaderInResponse() throws Exception {
+		this.spring.register(HpkpConfigTerminateConnection.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS,
+						"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS);
+	}
+
+	@Test
+	public void getWhenHpkpIncludeSubdomainThenPublicKeyPinsReportOnlyHeaderWithIncludeSubDomainsInResponse()
+			throws Exception {
+		this.spring.register(HpkpConfigIncludeSubDomains.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
+				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenHpkpWithReportUriThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() throws Exception {
+		this.spring.register(HpkpConfigWithReportURI.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
+				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenHpkpWithReportUriAsStringThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
+			throws Exception {
+		this.spring.register(HpkpConfigWithReportURIAsString.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
+				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenHpkpWithReportUriInLambdaThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
+			throws Exception {
+		this.spring.register(HpkpWithReportUriInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
+				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
+		this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'")).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
+	}
+
+	@Test
+	public void getWhenContentSecurityPolicyWithReportOnlyThenContentSecurityPolicyReportOnlyHeaderInResponse()
+			throws Exception {
+		this.spring.register(ContentSecurityPolicyReportOnlyConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
+						"default-src 'self'; script-src trustedscripts.example.com"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames())
+				.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
+	}
+
+	@Test
+	public void getWhenContentSecurityPolicyWithReportOnlyInLambdaThenContentSecurityPolicyReportOnlyHeaderInResponse()
+			throws Exception {
+		this.spring.register(ContentSecurityPolicyReportOnlyInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
+						"default-src 'self'; script-src trustedscripts.example.com"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames())
+				.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
+	}
+
+	@Test
+	public void configureWhenContentSecurityPolicyEmptyThenException() {
+		assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidConfig.class).autowire())
+				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void configureWhenContentSecurityPolicyEmptyInLambdaThenException() {
+		assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidInLambdaConfig.class).autowire())
+				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void configureWhenContentSecurityPolicyNoPolicyDirectivesInLambdaThenDefaultHeaderValue() throws Exception {
+		this.spring.register(ContentSecurityPolicyNoDirectivesInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'")).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
+	}
+
+	@Test
+	public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
+		this.spring.register(ReferrerPolicyDefaultConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy())).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
+	}
+
+	@Test
+	public void getWhenReferrerPolicyInLambdaThenReferrerPolicyHeaderInResponse() throws Exception {
+		this.spring.register(ReferrerPolicyDefaultInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy())).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
+	}
+
+	@Test
+	public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
+			throws Exception {
+		this.spring.register(ReferrerPolicyCustomConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy())).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
+	}
+
+	@Test
+	public void getWhenReferrerPolicyConfiguredWithCustomValueInLambdaThenCustomValueInResponse() throws Exception {
+		this.spring.register(ReferrerPolicyCustomInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy())).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
+	}
+
+	@Test
+	public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
+		this.spring.register(FeaturePolicyConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string("Feature-Policy", "geolocation 'self'")).andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Feature-Policy");
+	}
+
+	@Test
+	public void configureWhenFeaturePolicyEmptyThenException() {
+		assertThatThrownBy(() -> this.spring.register(FeaturePolicyInvalidConfig.class).autowire())
+				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse()
+			throws Exception {
+		this.spring.register(HstsWithPreloadConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header()
+				.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
+	}
+
+	@Test
+	public void getWhenHstsConfiguredWithPreloadInLambdaThenStrictTransportSecurityHeaderWithPreloadInResponse()
+			throws Exception {
+		this.spring.register(HstsWithPreloadInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header()
+				.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
+	}
+
+	@EnableWebSecurity
+	static class HeadersConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HeadersInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(withDefaults());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.contentTypeOptions();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ContentTypeOptionsInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.contentTypeOptions(withDefaults())
+				);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.frameOptions();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HstsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.httpStrictTransportSecurity();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CacheControlConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.cacheControl();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CacheControlInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.cacheControl(withDefaults())
+				);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.xssProtection();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class XssProtectionInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.xssProtection(withDefaults())
+				);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.frameOptions().sameOrigin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HeadersCustomSameOriginInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.frameOptions(frameOptionsConfig -> frameOptionsConfig.sameOrigin())
+				);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HpkpConfigNoPins extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.httpPublicKeyPinning();
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class HpkpConfig extends WebSecurityConfigurerAdapter {
 
@@ -440,18 +651,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpWithMultiplePinsThenPublicKeyPinsReportOnlyHeaderWithMultiplePinsInResponse()
-			throws Exception {
-		this.spring.register(HpkpConfigWithPins.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
-				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
-				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class HpkpConfigWithPins extends WebSecurityConfigurerAdapter {
 
@@ -472,17 +671,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpWithCustomAgeThenPublicKeyPinsReportOnlyHeaderWithCustomAgeInResponse() throws Exception {
-		this.spring.register(HpkpConfigCustomAge.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
-						"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class HpkpConfigCustomAge extends WebSecurityConfigurerAdapter {
 
@@ -500,17 +688,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpWithReportOnlyFalseThenPublicKeyPinsHeaderInResponse() throws Exception {
-		this.spring.register(HpkpConfigTerminateConnection.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS,
-						"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS);
-	}
-
 	@EnableWebSecurity
 	static class HpkpConfigTerminateConnection extends WebSecurityConfigurerAdapter {
 
@@ -528,18 +705,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpIncludeSubdomainThenPublicKeyPinsReportOnlyHeaderWithIncludeSubDomainsInResponse()
-			throws Exception {
-		this.spring.register(HpkpConfigIncludeSubDomains.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
-				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
-				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains"))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class HpkpConfigIncludeSubDomains extends WebSecurityConfigurerAdapter {
 
@@ -557,17 +722,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpWithReportUriThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() throws Exception {
-		this.spring.register(HpkpConfigWithReportURI.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
-				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
-				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class HpkpConfigWithReportURI extends WebSecurityConfigurerAdapter {
 
@@ -585,18 +739,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpWithReportUriAsStringThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
-			throws Exception {
-		this.spring.register(HpkpConfigWithReportURIAsString.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
-				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
-				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class HpkpConfigWithReportURIAsString extends WebSecurityConfigurerAdapter {
 
@@ -614,18 +756,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHpkpWithReportUriInLambdaThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
-			throws Exception {
-		this.spring.register(HpkpWithReportUriInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
-				HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
-				"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class HpkpWithReportUriInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -647,15 +777,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
-		this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'")).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
-	}
-
 	@EnableWebSecurity
 	static class ContentSecurityPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
 
@@ -671,19 +792,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenContentSecurityPolicyWithReportOnlyThenContentSecurityPolicyReportOnlyHeaderInResponse()
-			throws Exception {
-		this.spring.register(ContentSecurityPolicyReportOnlyConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
-						"default-src 'self'; script-src trustedscripts.example.com"))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames())
-				.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class ContentSecurityPolicyReportOnlyConfig extends WebSecurityConfigurerAdapter {
 
@@ -700,19 +808,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenContentSecurityPolicyWithReportOnlyInLambdaThenContentSecurityPolicyReportOnlyHeaderInResponse()
-			throws Exception {
-		this.spring.register(ContentSecurityPolicyReportOnlyInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
-						"default-src 'self'; script-src trustedscripts.example.com"))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames())
-				.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
-	}
-
 	@EnableWebSecurity
 	static class ContentSecurityPolicyReportOnlyInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -734,12 +829,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenContentSecurityPolicyEmptyThenException() {
-		assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidConfig.class).autowire())
-				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
-	}
-
 	@EnableWebSecurity
 	static class ContentSecurityPolicyInvalidConfig extends WebSecurityConfigurerAdapter {
 
@@ -755,12 +844,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenContentSecurityPolicyEmptyInLambdaThenException() {
-		assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidInLambdaConfig.class).autowire())
-				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
-	}
-
 	@EnableWebSecurity
 	static class ContentSecurityPolicyInvalidInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -780,15 +863,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenContentSecurityPolicyNoPolicyDirectivesInLambdaThenDefaultHeaderValue() throws Exception {
-		this.spring.register(ContentSecurityPolicyNoDirectivesInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'")).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
-	}
-
 	@EnableWebSecurity
 	static class ContentSecurityPolicyNoDirectivesInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -806,15 +880,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
-		this.spring.register(ReferrerPolicyDefaultConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy())).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
-	}
-
 	@EnableWebSecurity
 	static class ReferrerPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
 
@@ -830,15 +895,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenReferrerPolicyInLambdaThenReferrerPolicyHeaderInResponse() throws Exception {
-		this.spring.register(ReferrerPolicyDefaultInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy())).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
-	}
-
 	@EnableWebSecurity
 	static class ReferrerPolicyDefaultInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -856,16 +912,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
-			throws Exception {
-		this.spring.register(ReferrerPolicyCustomConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy())).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
-	}
-
 	@EnableWebSecurity
 	static class ReferrerPolicyCustomConfig extends WebSecurityConfigurerAdapter {
 
@@ -881,15 +927,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenReferrerPolicyConfiguredWithCustomValueInLambdaThenCustomValueInResponse() throws Exception {
-		this.spring.register(ReferrerPolicyCustomInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy())).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
-	}
-
 	@EnableWebSecurity
 	static class ReferrerPolicyCustomInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -909,15 +946,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
-		this.spring.register(FeaturePolicyConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
-				.andExpect(header().string("Feature-Policy", "geolocation 'self'")).andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Feature-Policy");
-	}
-
 	@EnableWebSecurity
 	static class FeaturePolicyConfig extends WebSecurityConfigurerAdapter {
 
@@ -933,12 +961,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenFeaturePolicyEmptyThenException() {
-		assertThatThrownBy(() -> this.spring.register(FeaturePolicyInvalidConfig.class).autowire())
-				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
-	}
-
 	@EnableWebSecurity
 	static class FeaturePolicyInvalidConfig extends WebSecurityConfigurerAdapter {
 
@@ -954,17 +976,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse()
-			throws Exception {
-		this.spring.register(HstsWithPreloadConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header()
-				.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload"))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
-	}
-
 	@EnableWebSecurity
 	static class HstsWithPreloadConfig extends WebSecurityConfigurerAdapter {
 
@@ -981,17 +992,6 @@ public class HeadersConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenHstsConfiguredWithPreloadInLambdaThenStrictTransportSecurityHeaderWithPreloadInResponse()
-			throws Exception {
-		this.spring.register(HstsWithPreloadInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header()
-				.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload"))
-				.andReturn();
-		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
-	}
-
 	@EnableWebSecurity
 	static class HstsWithPreloadInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
index c3649f7559..6353743976 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
@@ -71,6 +71,52 @@ public class HttpBasicConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(BasicAuthenticationFilter.class));
 	}
 
+	@Test
+	public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception {
+		this.spring.register(DefaultsLambdaEntryPointConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
+				.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
+	}
+
+	// SEC-2198
+	@Test
+	public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception {
+		this.spring.register(DefaultsEntryPointConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
+				.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
+	}
+
+	@Test
+	public void httpBasicWhenUsingCustomAuthenticationEntryPointThenResponseIncludesBasicChallenge() throws Exception {
+		this.spring.register(CustomAuthenticationEntryPointConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(CustomAuthenticationEntryPointConfig.ENTRY_POINT).commence(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any(AuthenticationException.class));
+	}
+
+	@Test
+	public void httpBasicWhenInvokedTwiceThenUsesOriginalEntryPoint() throws Exception {
+		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(DuplicateDoesNotOverrideConfig.ENTRY_POINT).commence(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any(AuthenticationException.class));
+	}
+
+	// SEC-3019
+	@Test
+	public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception {
+		this.spring.register(BasicUsesRememberMeConfig.class).autowire();
+
+		this.mvc.perform(get("/").with(httpBasic("user", "password")).param("remember-me", "true"))
+				.andExpect(cookie().exists("remember-me"));
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -100,14 +146,6 @@ public class HttpBasicConfigurerTests {
 
 	}
 
-	@Test
-	public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception {
-		this.spring.register(DefaultsLambdaEntryPointConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
-				.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
-	}
-
 	@EnableWebSecurity
 	static class DefaultsLambdaEntryPointConfig extends WebSecurityConfigurerAdapter {
 
@@ -133,15 +171,6 @@ public class HttpBasicConfigurerTests {
 
 	}
 
-	// SEC-2198
-	@Test
-	public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception {
-		this.spring.register(DefaultsEntryPointConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
-				.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
-	}
-
 	@EnableWebSecurity
 	static class DefaultsEntryPointConfig extends WebSecurityConfigurerAdapter {
 
@@ -166,16 +195,6 @@ public class HttpBasicConfigurerTests {
 
 	}
 
-	@Test
-	public void httpBasicWhenUsingCustomAuthenticationEntryPointThenResponseIncludesBasicChallenge() throws Exception {
-		this.spring.register(CustomAuthenticationEntryPointConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(CustomAuthenticationEntryPointConfig.ENTRY_POINT).commence(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any(AuthenticationException.class));
-	}
-
 	@EnableWebSecurity
 	static class CustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
 
@@ -203,16 +222,6 @@ public class HttpBasicConfigurerTests {
 
 	}
 
-	@Test
-	public void httpBasicWhenInvokedTwiceThenUsesOriginalEntryPoint() throws Exception {
-		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(DuplicateDoesNotOverrideConfig.ENTRY_POINT).commence(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any(AuthenticationException.class));
-	}
-
 	@EnableWebSecurity
 	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
@@ -242,15 +251,6 @@ public class HttpBasicConfigurerTests {
 
 	}
 
-	// SEC-3019
-	@Test
-	public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception {
-		this.spring.register(BasicUsesRememberMeConfig.class).autowire();
-
-		this.mvc.perform(get("/").with(httpBasic("user", "password")).param("remember-me", "true"))
-				.andExpect(cookie().exists("remember-me"));
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	static class BasicUsesRememberMeConfig extends WebSecurityConfigurerAdapter {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityAntMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityAntMatchersTests.java
index c78091f7dc..c6449818c2 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityAntMatchersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityAntMatchersTests.java
@@ -78,6 +78,25 @@ public class HttpSecurityAntMatchersTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
 	}
 
+	// SEC-3135
+	@Test
+	public void antMatchersMethodAndEmptyPatterns() throws Exception {
+		loadConfig(AntMatchersEmptyPatternsConfig.class);
+		this.request.setMethod("POST");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+	}
+
+	public void loadConfig(Class... configs) {
+		this.context = new AnnotationConfigWebApplicationContext();
+		this.context.register(configs);
+		this.context.refresh();
+
+		this.context.getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
 	@EnableWebSecurity
 	@Configuration
 	static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
@@ -104,17 +123,6 @@ public class HttpSecurityAntMatchersTests {
 
 	}
 
-	// SEC-3135
-	@Test
-	public void antMatchersMethodAndEmptyPatterns() throws Exception {
-		loadConfig(AntMatchersEmptyPatternsConfig.class);
-		this.request.setMethod("POST");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	static class AntMatchersEmptyPatternsConfig extends WebSecurityConfigurerAdapter {
@@ -142,12 +150,4 @@ public class HttpSecurityAntMatchersTests {
 
 	}
 
-	public void loadConfig(Class... configs) {
-		this.context = new AnnotationConfigWebApplicationContext();
-		this.context.register(configs);
-		this.context.refresh();
-
-		this.context.getAutowireCapableBeanFactory().autowireBean(this);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java
index 61989ec37f..6e2fed7cc1 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java
@@ -86,6 +86,14 @@ public class HttpSecurityLogoutTests {
 		assertThat(currentContext.getAuthentication()).isNotNull();
 	}
 
+	public void loadConfig(Class... configs) {
+		this.context = new AnnotationConfigWebApplicationContext();
+		this.context.register(configs);
+		this.context.refresh();
+
+		this.context.getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
 	@EnableWebSecurity
 	@Configuration
 	static class ClearAuthenticationFalseConfig extends WebSecurityConfigurerAdapter {
@@ -110,12 +118,4 @@ public class HttpSecurityLogoutTests {
 
 	}
 
-	public void loadConfig(Class... configs) {
-		this.context = new AnnotationConfigWebApplicationContext();
-		this.context.register(configs);
-		this.context.refresh();
-
-		this.context.getAutowireCapableBeanFactory().autowireBean(this);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
index 606c164b8e..eb07fa41bf 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
@@ -105,6 +105,119 @@ public class HttpSecurityRequestMatchersTests {
 		assertThat(this.springSecurityFilterChain.getFilters("/path")).isNotEmpty();
 	}
 
+	@Test
+	public void requestMatchersMvcMatcher() throws Exception {
+		loadConfig(RequestMatchersMvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
+
+		this.request.setServletPath("/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/path.html");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/path/");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+	}
+
+	@Test
+	public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception {
+		loadConfig(RequestMatchersMvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
+
+		this.request.setServletPath("/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/path.html");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("/path/");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+	}
+
+	@Test
+	public void requestMatchersMvcMatcherServletPath() throws Exception {
+		loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("");
+		this.request.setRequestURI("/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		setup();
+
+		this.request.setServletPath("/other");
+		this.request.setRequestURI("/other/path");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+	}
+
+	@Test
+	public void requestMatcherWhensMvcMatcherServletPathInLambdaThenPathIsSecured() throws Exception {
+		loadConfig(RequestMatchersMvcMatcherServletPathInLambdaConfig.class);
+
+		this.request.setServletPath("/spring");
+		this.request.setRequestURI("/spring/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setServletPath("");
+		this.request.setRequestURI("/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+		setup();
+
+		this.request.setServletPath("/other");
+		this.request.setRequestURI("/other/path");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+	}
+
+	public void loadConfig(Class... configs) {
+		this.context = new AnnotationConfigWebApplicationContext();
+		this.context.register(configs);
+		this.context.setServletContext(new MockServletContext());
+		this.context.refresh();
+
+		this.context.getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -141,30 +254,6 @@ public class HttpSecurityRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestMatchersMvcMatcher() throws Exception {
-		loadConfig(RequestMatchersMvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
-
-		this.request.setServletPath("/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/path.html");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/path/");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -203,30 +292,6 @@ public class HttpSecurityRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception {
-		loadConfig(RequestMatchersMvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
-
-		this.request.setServletPath("/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/path.html");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("/path/");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -260,34 +325,6 @@ public class HttpSecurityRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestMatchersMvcMatcherServletPath() throws Exception {
-		loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("");
-		this.request.setRequestURI("/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		setup();
-
-		this.request.setServletPath("/other");
-		this.request.setRequestURI("/other/path");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -327,34 +364,6 @@ public class HttpSecurityRequestMatchersTests {
 
 	}
 
-	@Test
-	public void requestMatcherWhensMvcMatcherServletPathInLambdaThenPathIsSecured() throws Exception {
-		loadConfig(RequestMatchersMvcMatcherServletPathInLambdaConfig.class);
-
-		this.request.setServletPath("/spring");
-		this.request.setRequestURI("/spring/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
-
-		setup();
-
-		this.request.setServletPath("");
-		this.request.setRequestURI("/path");
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-
-		setup();
-
-		this.request.setServletPath("/other");
-		this.request.setRequestURI("/other/path");
-
-		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
-
-		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -399,13 +408,4 @@ public class HttpSecurityRequestMatchersTests {
 
 	}
 
-	public void loadConfig(Class... configs) {
-		this.context = new AnnotationConfigWebApplicationContext();
-		this.context.register(configs);
-		this.context.setServletContext(new MockServletContext());
-		this.context.refresh();
-
-		this.context.getAutowireCapableBeanFactory().autowireBean(this);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/Issue55Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/Issue55Tests.java
index 5097a3d5ef..b071eadbb0 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/Issue55Tests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/Issue55Tests.java
@@ -60,6 +60,36 @@ public class Issue55Tests {
 		assertThat(filter.getAuthenticationManager().authenticate(token)).isEqualTo(CustomAuthenticationManager.RESULT);
 	}
 
+	@Test
+	public void multiHttpWebSecurityConfigurerAdapterDefaultsToAutowired()
+			throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+		TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this");
+		this.spring.register(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig.class);
+		this.spring.getContext().getBean(FilterChainProxy.class);
+
+		FilterSecurityInterceptor filter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class, 0);
+		assertThat(filter.getAuthenticationManager().authenticate(token)).isEqualTo(CustomAuthenticationManager.RESULT);
+
+		FilterSecurityInterceptor secondFilter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class,
+				1);
+		assertThat(secondFilter.getAuthenticationManager().authenticate(token))
+				.isEqualTo(CustomAuthenticationManager.RESULT);
+	}
+
+	Filter findFilter(Class filter, int index) {
+		List filters = filterChain(index).getFilters();
+		for (Filter it : filters) {
+			if (filter.isAssignableFrom(it.getClass())) {
+				return it;
+			}
+		}
+		return null;
+	}
+
+	SecurityFilterChain filterChain(int index) {
+		return this.spring.getContext().getBean(FilterChainProxy.class).getFilterChains().get(index);
+	}
+
 	@EnableWebSecurity
 	static class WebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
 
@@ -89,22 +119,6 @@ public class Issue55Tests {
 
 	}
 
-	@Test
-	public void multiHttpWebSecurityConfigurerAdapterDefaultsToAutowired()
-			throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-		TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this");
-		this.spring.register(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig.class);
-		this.spring.getContext().getBean(FilterChainProxy.class);
-
-		FilterSecurityInterceptor filter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class, 0);
-		assertThat(filter.getAuthenticationManager().authenticate(token)).isEqualTo(CustomAuthenticationManager.RESULT);
-
-		FilterSecurityInterceptor secondFilter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class,
-				1);
-		assertThat(secondFilter.getAuthenticationManager().authenticate(token))
-				.isEqualTo(CustomAuthenticationManager.RESULT);
-	}
-
 	@EnableWebSecurity
 	static class MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
 
@@ -160,18 +174,4 @@ public class Issue55Tests {
 
 	}
 
-	Filter findFilter(Class filter, int index) {
-		List filters = filterChain(index).getFilters();
-		for (Filter it : filters) {
-			if (filter.isAssignableFrom(it.getClass())) {
-				return it;
-			}
-		}
-		return null;
-	}
-
-	SecurityFilterChain filterChain(int index) {
-		return this.spring.getContext().getBean(FilterChainProxy.class).getFilterChains().get(index);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
index e70283bb82..46b097a6b9 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
@@ -75,6 +75,63 @@ public class JeeConfigurerTests {
 				.postProcess(any(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class));
 	}
 
+	@Test
+	public void jeeWhenInvokedTwiceThenUsesOriginalMappableRoles() throws Exception {
+		this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
+		Principal user = mock(Principal.class);
+		when(user.getName()).thenReturn("user");
+
+		this.mvc.perform(get("/").principal(user).with(request -> {
+			request.addUserRole("ROLE_ADMIN");
+			request.addUserRole("ROLE_USER");
+			return request;
+		})).andExpect(authenticated().withRoles("USER"));
+	}
+
+	@Test
+	public void requestWhenJeeMappableRolesInLambdaThenAuthenticatedWithMappableRoles() throws Exception {
+		this.spring.register(JeeMappableRolesConfig.class).autowire();
+		Principal user = mock(Principal.class);
+		when(user.getName()).thenReturn("user");
+
+		this.mvc.perform(get("/").principal(user).with(request -> {
+			request.addUserRole("ROLE_ADMIN");
+			request.addUserRole("ROLE_USER");
+			return request;
+		})).andExpect(authenticated().withRoles("USER"));
+	}
+
+	@Test
+	public void requestWhenJeeMappableAuthoritiesInLambdaThenAuthenticatedWithMappableAuthorities() throws Exception {
+		this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
+		Principal user = mock(Principal.class);
+		when(user.getName()).thenReturn("user");
+
+		this.mvc.perform(get("/").principal(user).with(request -> {
+			request.addUserRole("ROLE_ADMIN");
+			request.addUserRole("ROLE_USER");
+			return request;
+		})).andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER")));
+	}
+
+	@Test
+	public void requestWhenCustomAuthenticatedUserDetailsServiceInLambdaThenCustomAuthenticatedUserDetailsServiceUsed()
+			throws Exception {
+		this.spring.register(JeeCustomAuthenticatedUserDetailsServiceConfig.class).autowire();
+		Principal user = mock(Principal.class);
+		User userDetails = new User("user", "N/A", true, true, true, true,
+				AuthorityUtils.createAuthorityList("ROLE_USER"));
+		when(user.getName()).thenReturn("user");
+		when(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
+				.thenReturn(userDetails);
+
+		this.mvc.perform(get("/").principal(user).with(request -> {
+			request.addUserRole("ROLE_ADMIN");
+			request.addUserRole("ROLE_USER");
+			return request;
+		})).andExpect(authenticated().withRoles("USER"));
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -104,19 +161,6 @@ public class JeeConfigurerTests {
 
 	}
 
-	@Test
-	public void jeeWhenInvokedTwiceThenUsesOriginalMappableRoles() throws Exception {
-		this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
-		Principal user = mock(Principal.class);
-		when(user.getName()).thenReturn("user");
-
-		this.mvc.perform(get("/").principal(user).with(request -> {
-			request.addUserRole("ROLE_ADMIN");
-			request.addUserRole("ROLE_USER");
-			return request;
-		})).andExpect(authenticated().withRoles("USER"));
-	}
-
 	@EnableWebSecurity
 	static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
 
@@ -133,19 +177,6 @@ public class JeeConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenJeeMappableRolesInLambdaThenAuthenticatedWithMappableRoles() throws Exception {
-		this.spring.register(JeeMappableRolesConfig.class).autowire();
-		Principal user = mock(Principal.class);
-		when(user.getName()).thenReturn("user");
-
-		this.mvc.perform(get("/").principal(user).with(request -> {
-			request.addUserRole("ROLE_ADMIN");
-			request.addUserRole("ROLE_USER");
-			return request;
-		})).andExpect(authenticated().withRoles("USER"));
-	}
-
 	@EnableWebSecurity
 	public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
 
@@ -166,19 +197,6 @@ public class JeeConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenJeeMappableAuthoritiesInLambdaThenAuthenticatedWithMappableAuthorities() throws Exception {
-		this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
-		Principal user = mock(Principal.class);
-		when(user.getName()).thenReturn("user");
-
-		this.mvc.perform(get("/").principal(user).with(request -> {
-			request.addUserRole("ROLE_ADMIN");
-			request.addUserRole("ROLE_USER");
-			return request;
-		})).andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER")));
-	}
-
 	@EnableWebSecurity
 	public static class JeeMappableAuthoritiesConfig extends WebSecurityConfigurerAdapter {
 
@@ -199,24 +217,6 @@ public class JeeConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenCustomAuthenticatedUserDetailsServiceInLambdaThenCustomAuthenticatedUserDetailsServiceUsed()
-			throws Exception {
-		this.spring.register(JeeCustomAuthenticatedUserDetailsServiceConfig.class).autowire();
-		Principal user = mock(Principal.class);
-		User userDetails = new User("user", "N/A", true, true, true, true,
-				AuthorityUtils.createAuthorityList("ROLE_USER"));
-		when(user.getName()).thenReturn("user");
-		when(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
-				.thenReturn(userDetails);
-
-		this.mvc.perform(get("/").principal(user).with(request -> {
-			request.addUserRole("ROLE_ADMIN");
-			request.addUserRole("ROLE_USER");
-			return request;
-		})).andExpect(authenticated().withRoles("USER"));
-	}
-
 	@EnableWebSecurity
 	public static class JeeCustomAuthenticatedUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
index 6e1669710b..4d3905976b 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
@@ -70,82 +70,24 @@ public class LogoutConfigurerTests {
 				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
 	}
 
-	@EnableWebSecurity
-	static class NullLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout()
-					.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class));
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenDefaultLogoutSuccessHandlerForHasNullLogoutHandlerInLambdaThenException() {
 		assertThatThrownBy(() -> this.spring.register(NullLogoutSuccessHandlerInLambdaConfig.class).autowire())
 				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
 	}
 
-	@EnableWebSecurity
-	static class NullLogoutSuccessHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout(logout ->
-					logout.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class))
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherThenException() {
 		assertThatThrownBy(() -> this.spring.register(NullMatcherConfig.class).autowire())
 				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
 	}
 
-	@EnableWebSecurity
-	static class NullMatcherConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout()
-					.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherInLambdaThenException() {
 		assertThatThrownBy(() -> this.spring.register(NullMatcherInLambdaConfig.class).autowire())
 				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
 	}
 
-	@EnableWebSecurity
-	static class NullMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout(logout ->
-					logout.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null)
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLogoutFilter() {
 		this.spring.register(ObjectPostProcessorConfig.class).autowire();
@@ -153,35 +95,6 @@ public class LogoutConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(LogoutFilter.class));
 	}
 
-	@EnableWebSecurity
-	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
-
-		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout();
-			// @formatter:on
-		}
-
-		@Bean
-		static ObjectPostProcessor objectPostProcessor() {
-			return objectPostProcessor;
-		}
-
-	}
-
-	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
-
-		@Override
-		public  O postProcess(O object) {
-			return object;
-		}
-
-	}
-
 	@Test
 	public void logoutWhenInvokedTwiceThenUsesOriginalLogoutUrl() throws Exception {
 		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
@@ -190,30 +103,6 @@ public class LogoutConfigurerTests {
 				.andExpect(redirectedUrl("/login?logout"));
 	}
 
-	@EnableWebSecurity
-	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout()
-					.logoutUrl("/custom/logout")
-					.and()
-				.logout();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-2311
 	@Test
 	public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
@@ -243,21 +132,6 @@ public class LogoutConfigurerTests {
 		this.mvc.perform(delete("/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
 	}
 
-	@EnableWebSecurity
-	static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf()
-					.disable()
-				.logout();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void logoutWhenGetRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
 		this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
@@ -288,22 +162,6 @@ public class LogoutConfigurerTests {
 				.andExpect(redirectedUrl("/login?logout"));
 	}
 
-	@EnableWebSecurity
-	static class CsrfDisabledAndCustomLogoutConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf()
-					.disable()
-				.logout()
-					.logoutUrl("/custom/logout");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
 		this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire();
@@ -311,21 +169,6 @@ public class LogoutConfigurerTests {
 		this.mvc.perform(get("/custom/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
 	}
 
-	@EnableWebSecurity
-	static class CsrfDisabledAndCustomLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.csrf()
-					.disable()
-				.logout(logout -> logout.logoutUrl("/custom/logout"));
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-3170
 	@Test
 	public void configureWhenLogoutHandlerNullThenException() {
@@ -333,39 +176,12 @@ public class LogoutConfigurerTests {
 				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
 	}
 
-	@EnableWebSecurity
-	static class NullLogoutHandlerConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout()
-					.addLogoutHandler(null);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenLogoutHandlerNullInLambdaThenException() {
 		assertThatThrownBy(() -> this.spring.register(NullLogoutHandlerInLambdaConfig.class).autowire())
 				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class);
 	}
 
-	@EnableWebSecurity
-	static class NullLogoutHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.logout(logout -> logout.addLogoutHandler(null));
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-3170
 	@Test
 	public void rememberMeWhenRememberMeServicesNotLogoutHandlerThenRedirectsToLogin() throws Exception {
@@ -375,22 +191,6 @@ public class LogoutConfigurerTests {
 				.andExpect(redirectedUrl("/login?logout"));
 	}
 
-	@EnableWebSecurity
-	static class RememberMeNoLogoutHandler extends WebSecurityConfigurerAdapter {
-
-		static RememberMeServices REMEMBER_ME = mock(RememberMeServices.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.rememberMe()
-					.rememberMeServices(REMEMBER_ME);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void logoutWhenAcceptTextHtmlThenRedirectsToLogin() throws Exception {
 		this.spring.register(BasicSecurityConfig.class).autowire();
@@ -439,11 +239,6 @@ public class LogoutConfigurerTests {
 				.andExpect(status().isNoContent());
 	}
 
-	@EnableWebSecurity
-	static class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
-
-	}
-
 	@Test
 	public void logoutWhenDisabledThenLogoutUrlNotFound() throws Exception {
 		this.spring.register(LogoutDisabledConfig.class).autowire();
@@ -451,6 +246,211 @@ public class LogoutConfigurerTests {
 		this.mvc.perform(post("/logout").with(csrf())).andExpect(status().isNotFound());
 	}
 
+	@EnableWebSecurity
+	static class NullLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout()
+					.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class));
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NullLogoutSuccessHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout(logout ->
+					logout.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class))
+				);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NullMatcherConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout()
+					.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NullMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout(logout ->
+					logout.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null)
+				);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
+
+		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout();
+			// @formatter:on
+		}
+
+		@Bean
+		static ObjectPostProcessor objectPostProcessor() {
+			return objectPostProcessor;
+		}
+
+	}
+
+	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
+
+		@Override
+		public  O postProcess(O object) {
+			return object;
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout()
+					.logoutUrl("/custom/logout")
+					.and()
+				.logout();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf()
+					.disable()
+				.logout();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CsrfDisabledAndCustomLogoutConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf()
+					.disable()
+				.logout()
+					.logoutUrl("/custom/logout");
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class CsrfDisabledAndCustomLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf()
+					.disable()
+				.logout(logout -> logout.logoutUrl("/custom/logout"));
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NullLogoutHandlerConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout()
+					.addLogoutHandler(null);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class NullLogoutHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout(logout -> logout.addLogoutHandler(null));
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RememberMeNoLogoutHandler extends WebSecurityConfigurerAdapter {
+
+		static RememberMeServices REMEMBER_ME = mock(RememberMeServices.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.rememberMe()
+					.rememberMeServices(REMEMBER_ME);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
+
+	}
+
 	@EnableWebSecurity
 	static class LogoutDisabledConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java
index c386e59c80..79c48708c1 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java
@@ -61,11 +61,6 @@ public class NamespaceDebugTests {
 		verify(appender, atLeastOnce()).doAppend(any(ILoggingEvent.class));
 	}
 
-	@EnableWebSecurity(debug = true)
-	static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
-
-	}
-
 	@Test
 	public void requestWhenDebugSetToFalseThenDoesNotLogDebugInformation() throws Exception {
 		Appender appender = mockAppenderFor("Spring Security Debugger");
@@ -75,11 +70,6 @@ public class NamespaceDebugTests {
 		verify(appender, never()).doAppend(any(ILoggingEvent.class));
 	}
 
-	@EnableWebSecurity
-	static class NoDebugWebSecurity extends WebSecurityConfigurerAdapter {
-
-	}
-
 	private Appender mockAppenderFor(String name) {
 		Appender appender = mock(Appender.class);
 		Logger logger = (Logger) LoggerFactory.getLogger(name);
@@ -92,4 +82,14 @@ public class NamespaceDebugTests {
 		return this.spring.getContext().getBean("springSecurityFilterChain").getClass();
 	}
 
+	@EnableWebSecurity(debug = true)
+	static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
+
+	}
+
+	@EnableWebSecurity
+	static class NoDebugWebSecurity extends WebSecurityConfigurerAdapter {
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java
index ccf73dba40..1ff61c858c 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java
@@ -60,6 +60,30 @@ public class NamespaceHttpAnonymousTests {
 		this.mvc.perform(get("/type")).andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
 	}
 
+	@Test
+	public void anonymousRequestWhenDisablingAnonymousThenDenies() throws Exception {
+		this.spring.register(AnonymousDisabledConfig.class, AnonymousController.class).autowire();
+		this.mvc.perform(get("/type")).andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void requestWhenAnonymousThenSendsAnonymousConfiguredAuthorities() throws Exception {
+		this.spring.register(AnonymousGrantedAuthorityConfig.class, AnonymousController.class).autowire();
+		this.mvc.perform(get("/type")).andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
+	}
+
+	@Test
+	public void anonymousRequestWhenAnonymousKeyConfiguredThenKeyIsUsed() throws Exception {
+		this.spring.register(AnonymousKeyConfig.class, AnonymousController.class).autowire();
+		this.mvc.perform(get("/key")).andExpect(content().string(String.valueOf("AnonymousKeyConfig".hashCode())));
+	}
+
+	@Test
+	public void anonymousRequestWhenAnonymousUsernameConfiguredThenUsernameIsUsed() throws Exception {
+		this.spring.register(AnonymousUsernameConfig.class, AnonymousController.class).autowire();
+		this.mvc.perform(get("/principal")).andExpect(content().string("AnonymousUsernameConfig"));
+	}
+
 	@EnableWebSecurity
 	static class AnonymousConfig extends WebSecurityConfigurerAdapter {
 
@@ -75,12 +99,6 @@ public class NamespaceHttpAnonymousTests {
 
 	}
 
-	@Test
-	public void anonymousRequestWhenDisablingAnonymousThenDenies() throws Exception {
-		this.spring.register(AnonymousDisabledConfig.class, AnonymousController.class).autowire();
-		this.mvc.perform(get("/type")).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class AnonymousDisabledConfig extends WebSecurityConfigurerAdapter {
 
@@ -107,12 +125,6 @@ public class NamespaceHttpAnonymousTests {
 
 	}
 
-	@Test
-	public void requestWhenAnonymousThenSendsAnonymousConfiguredAuthorities() throws Exception {
-		this.spring.register(AnonymousGrantedAuthorityConfig.class, AnonymousController.class).autowire();
-		this.mvc.perform(get("/type")).andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
-	}
-
 	@EnableWebSecurity
 	static class AnonymousGrantedAuthorityConfig extends WebSecurityConfigurerAdapter {
 
@@ -131,12 +143,6 @@ public class NamespaceHttpAnonymousTests {
 
 	}
 
-	@Test
-	public void anonymousRequestWhenAnonymousKeyConfiguredThenKeyIsUsed() throws Exception {
-		this.spring.register(AnonymousKeyConfig.class, AnonymousController.class).autowire();
-		this.mvc.perform(get("/key")).andExpect(content().string(String.valueOf("AnonymousKeyConfig".hashCode())));
-	}
-
 	@EnableWebSecurity
 	static class AnonymousKeyConfig extends WebSecurityConfigurerAdapter {
 
@@ -154,12 +160,6 @@ public class NamespaceHttpAnonymousTests {
 
 	}
 
-	@Test
-	public void anonymousRequestWhenAnonymousUsernameConfiguredThenUsernameIsUsed() throws Exception {
-		this.spring.register(AnonymousUsernameConfig.class, AnonymousController.class).autowire();
-		this.mvc.perform(get("/principal")).andExpect(content().string("AnonymousUsernameConfig"));
-	}
-
 	@EnableWebSecurity
 	static class AnonymousUsernameConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
index 6cd603b95b..153c5e28dd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
@@ -73,6 +73,90 @@ public class NamespaceHttpBasicTests {
 		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
 	}
 
+	@Test
+	public void basicAuthenticationWhenUsingDefaultsInLambdaThenMatchesNamespace() throws Exception {
+		this.spring.register(HttpBasicLambdaConfig.class, UserConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
+
+		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
+				.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
+
+		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
+	}
+
+	/**
+	 * http@realm equivalent
+	 */
+	@Test
+	public void basicAuthenticationWhenUsingCustomRealmThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomHttpBasicConfig.class, UserConfig.class).autowire();
+
+		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
+				.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
+	}
+
+	@Test
+	public void basicAuthenticationWhenUsingCustomRealmInLambdaThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomHttpBasicLambdaConfig.class, UserConfig.class).autowire();
+
+		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
+				.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
+	}
+
+	/**
+	 * http/http-basic@authentication-details-source-ref equivalent
+	 */
+	@Test
+	public void basicAuthenticationWhenUsingAuthenticationDetailsSourceRefThenMatchesNamespace() throws Exception {
+		this.spring.register(AuthenticationDetailsSourceHttpBasicConfig.class, UserConfig.class).autowire();
+
+		AuthenticationDetailsSource source = this.spring.getContext()
+				.getBean(AuthenticationDetailsSource.class);
+
+		this.mvc.perform(get("/").with(httpBasic("user", "password")));
+
+		verify(source).buildDetails(any(HttpServletRequest.class));
+	}
+
+	@Test
+	public void basicAuthenticationWhenUsingAuthenticationDetailsSourceRefInLambdaThenMatchesNamespace()
+			throws Exception {
+		this.spring.register(AuthenticationDetailsSourceHttpBasicLambdaConfig.class, UserConfig.class).autowire();
+
+		AuthenticationDetailsSource source = this.spring.getContext()
+				.getBean(AuthenticationDetailsSource.class);
+
+		this.mvc.perform(get("/").with(httpBasic("user", "password")));
+
+		verify(source).buildDetails(any(HttpServletRequest.class));
+	}
+
+	/**
+	 * http/http-basic@entry-point-ref
+	 */
+	@Test
+	public void basicAuthenticationWhenUsingEntryPointRefThenMatchesNamespace() throws Exception {
+		this.spring.register(EntryPointRefHttpBasicConfig.class, UserConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().is(999));
+
+		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().is(999));
+
+		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
+	}
+
+	@Test
+	public void basicAuthenticationWhenUsingEntryPointRefInLambdaThenMatchesNamespace() throws Exception {
+		this.spring.register(EntryPointRefHttpBasicLambdaConfig.class, UserConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(status().is(999));
+
+		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().is(999));
+
+		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
+	}
+
 	@Configuration
 	static class UserConfig {
 
@@ -107,18 +191,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	@Test
-	public void basicAuthenticationWhenUsingDefaultsInLambdaThenMatchesNamespace() throws Exception {
-		this.spring.register(HttpBasicLambdaConfig.class, UserConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
-
-		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
-				.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
-
-		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
-	}
-
 	@EnableWebSecurity
 	static class HttpBasicLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -136,17 +208,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	/**
-	 * http@realm equivalent
-	 */
-	@Test
-	public void basicAuthenticationWhenUsingCustomRealmThenMatchesNamespace() throws Exception {
-		this.spring.register(CustomHttpBasicConfig.class, UserConfig.class).autowire();
-
-		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
-				.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
-	}
-
 	@EnableWebSecurity
 	static class CustomHttpBasicConfig extends WebSecurityConfigurerAdapter {
 
@@ -163,14 +224,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	@Test
-	public void basicAuthenticationWhenUsingCustomRealmInLambdaThenMatchesNamespace() throws Exception {
-		this.spring.register(CustomHttpBasicLambdaConfig.class, UserConfig.class).autowire();
-
-		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
-				.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
-	}
-
 	@EnableWebSecurity
 	static class CustomHttpBasicLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -188,21 +241,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	/**
-	 * http/http-basic@authentication-details-source-ref equivalent
-	 */
-	@Test
-	public void basicAuthenticationWhenUsingAuthenticationDetailsSourceRefThenMatchesNamespace() throws Exception {
-		this.spring.register(AuthenticationDetailsSourceHttpBasicConfig.class, UserConfig.class).autowire();
-
-		AuthenticationDetailsSource source = this.spring.getContext()
-				.getBean(AuthenticationDetailsSource.class);
-
-		this.mvc.perform(get("/").with(httpBasic("user", "password")));
-
-		verify(source).buildDetails(any(HttpServletRequest.class));
-	}
-
 	@EnableWebSecurity
 	static class AuthenticationDetailsSourceHttpBasicConfig extends WebSecurityConfigurerAdapter {
 
@@ -225,19 +263,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	@Test
-	public void basicAuthenticationWhenUsingAuthenticationDetailsSourceRefInLambdaThenMatchesNamespace()
-			throws Exception {
-		this.spring.register(AuthenticationDetailsSourceHttpBasicLambdaConfig.class, UserConfig.class).autowire();
-
-		AuthenticationDetailsSource source = this.spring.getContext()
-				.getBean(AuthenticationDetailsSource.class);
-
-		this.mvc.perform(get("/").with(httpBasic("user", "password")));
-
-		verify(source).buildDetails(any(HttpServletRequest.class));
-	}
-
 	@EnableWebSecurity
 	static class AuthenticationDetailsSourceHttpBasicLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -260,20 +285,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	/**
-	 * http/http-basic@entry-point-ref
-	 */
-	@Test
-	public void basicAuthenticationWhenUsingEntryPointRefThenMatchesNamespace() throws Exception {
-		this.spring.register(EntryPointRefHttpBasicConfig.class, UserConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().is(999));
-
-		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().is(999));
-
-		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
-	}
-
 	@EnableWebSecurity
 	static class EntryPointRefHttpBasicConfig extends WebSecurityConfigurerAdapter {
 
@@ -293,17 +304,6 @@ public class NamespaceHttpBasicTests {
 
 	}
 
-	@Test
-	public void basicAuthenticationWhenUsingEntryPointRefInLambdaThenMatchesNamespace() throws Exception {
-		this.spring.register(EntryPointRefHttpBasicLambdaConfig.class, UserConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(status().is(999));
-
-		this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().is(999));
-
-		this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
-	}
-
 	@EnableWebSecurity
 	static class EntryPointRefHttpBasicLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java
index e2bc0970fd..4355601aa9 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java
@@ -65,6 +65,37 @@ public class NamespaceHttpCustomFilterTests {
 		assertThatFilters().containsSubsequence(CustomFilter.class, UsernamePasswordAuthenticationFilter.class);
 	}
 
+	@Test
+	public void getFiltersWhenFilterAddedAfterThenBehaviorMatchesNamespace() {
+		this.spring.register(CustomFilterAfterConfig.class, UserDetailsServiceConfig.class).autowire();
+		assertThatFilters().containsSubsequence(UsernamePasswordAuthenticationFilter.class, CustomFilter.class);
+	}
+
+	@Test
+	public void getFiltersWhenFilterAddedThenBehaviorMatchesNamespace() {
+		this.spring.register(CustomFilterPositionConfig.class, UserDetailsServiceConfig.class).autowire();
+		assertThatFilters().containsExactly(CustomFilter.class);
+	}
+
+	@Test
+	public void getFiltersWhenFilterAddedAtPositionThenBehaviorMatchesNamespace() {
+		this.spring.register(CustomFilterPositionAtConfig.class, UserDetailsServiceConfig.class).autowire();
+		assertThatFilters().containsExactly(OtherCustomFilter.class);
+	}
+
+	@Test
+	public void getFiltersWhenCustomAuthenticationManagerThenBehaviorMatchesNamespace() {
+		this.spring.register(NoAuthenticationManagerInHttpConfigurationConfig.class).autowire();
+		assertThatFilters().startsWith(CustomFilter.class);
+	}
+
+	private ListAssert> assertThatFilters() {
+		FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
+		List> filters = filterChain.getFilters("/").stream().map(Object::getClass)
+				.collect(Collectors.toList());
+		return assertThat(filters);
+	}
+
 	@EnableWebSecurity
 	static class CustomFilterBeforeConfig extends WebSecurityConfigurerAdapter {
 
@@ -79,12 +110,6 @@ public class NamespaceHttpCustomFilterTests {
 
 	}
 
-	@Test
-	public void getFiltersWhenFilterAddedAfterThenBehaviorMatchesNamespace() {
-		this.spring.register(CustomFilterAfterConfig.class, UserDetailsServiceConfig.class).autowire();
-		assertThatFilters().containsSubsequence(UsernamePasswordAuthenticationFilter.class, CustomFilter.class);
-	}
-
 	@EnableWebSecurity
 	static class CustomFilterAfterConfig extends WebSecurityConfigurerAdapter {
 
@@ -99,12 +124,6 @@ public class NamespaceHttpCustomFilterTests {
 
 	}
 
-	@Test
-	public void getFiltersWhenFilterAddedThenBehaviorMatchesNamespace() {
-		this.spring.register(CustomFilterPositionConfig.class, UserDetailsServiceConfig.class).autowire();
-		assertThatFilters().containsExactly(CustomFilter.class);
-	}
-
 	@EnableWebSecurity
 	static class CustomFilterPositionConfig extends WebSecurityConfigurerAdapter {
 
@@ -125,12 +144,6 @@ public class NamespaceHttpCustomFilterTests {
 
 	}
 
-	@Test
-	public void getFiltersWhenFilterAddedAtPositionThenBehaviorMatchesNamespace() {
-		this.spring.register(CustomFilterPositionAtConfig.class, UserDetailsServiceConfig.class).autowire();
-		assertThatFilters().containsExactly(OtherCustomFilter.class);
-	}
-
 	@EnableWebSecurity
 	static class CustomFilterPositionAtConfig extends WebSecurityConfigurerAdapter {
 
@@ -149,12 +162,6 @@ public class NamespaceHttpCustomFilterTests {
 
 	}
 
-	@Test
-	public void getFiltersWhenCustomAuthenticationManagerThenBehaviorMatchesNamespace() {
-		this.spring.register(NoAuthenticationManagerInHttpConfigurationConfig.class).autowire();
-		assertThatFilters().startsWith(CustomFilter.class);
-	}
-
 	@EnableWebSecurity
 	static class NoAuthenticationManagerInHttpConfigurationConfig extends WebSecurityConfigurerAdapter {
 
@@ -220,11 +227,4 @@ public class NamespaceHttpCustomFilterTests {
 
 	}
 
-	private ListAssert> assertThatFilters() {
-		FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
-		List> filters = filterChain.getFilters("/").stream().map(Object::getClass)
-				.collect(Collectors.toList());
-		return assertThat(filters);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java
index eeab7c3e11..ac14a32ba3 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java
@@ -70,6 +70,10 @@ public class NamespaceHttpExpressionHandlerTests {
 		verifyBean("expressionParser", ExpressionParser.class).parseExpression("hasRole('USER')");
 	}
 
+	private  T verifyBean(String beanName, Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanName, beanClass));
+	}
+
 	@EnableWebMvc
 	@EnableWebSecurity
 	private static class ExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
@@ -115,8 +119,4 @@ public class NamespaceHttpExpressionHandlerTests {
 
 	}
 
-	private  T verifyBean(String beanName, Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanName, beanClass));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFirewallTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFirewallTests.java
index 146db2013d..7ddce408dd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFirewallTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFirewallTests.java
@@ -56,11 +56,6 @@ public class NamespaceHttpFirewallTests {
 		assertThatCode(() -> this.mvc.perform(get("/public/../private/"))).isInstanceOf(RequestRejectedException.class);
 	}
 
-	@EnableWebSecurity
-	static class HttpFirewallConfig {
-
-	}
-
 	@Test
 	public void requestWithCustomFirewallThenBehaviorMatchesNamespace() {
 		this.rule.register(CustomHttpFirewallConfig.class).autowire();
@@ -68,6 +63,18 @@ public class NamespaceHttpFirewallTests {
 				.isInstanceOf(RequestRejectedException.class);
 	}
 
+	@Test
+	public void requestWithCustomFirewallBeanThenBehaviorMatchesNamespace() {
+		this.rule.register(CustomHttpFirewallBeanConfig.class).autowire();
+		assertThatCode(() -> this.mvc.perform(get("/").param("deny", "true")))
+				.isInstanceOf(RequestRejectedException.class);
+	}
+
+	@EnableWebSecurity
+	static class HttpFirewallConfig {
+
+	}
+
 	@EnableWebSecurity
 	static class CustomHttpFirewallConfig extends WebSecurityConfigurerAdapter {
 
@@ -78,13 +85,6 @@ public class NamespaceHttpFirewallTests {
 
 	}
 
-	@Test
-	public void requestWithCustomFirewallBeanThenBehaviorMatchesNamespace() {
-		this.rule.register(CustomHttpFirewallBeanConfig.class).autowire();
-		assertThatCode(() -> this.mvc.perform(get("/").param("deny", "true")))
-				.isInstanceOf(RequestRejectedException.class);
-	}
-
 	@EnableWebSecurity
 	static class CustomHttpFirewallBeanConfig {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java
index 7dd2827975..6a8b15d8a2 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java
@@ -71,6 +71,36 @@ public class NamespaceHttpFormLoginTests {
 				.andExpect(redirectedUrl("/"));
 	}
 
+	@Test
+	public void formLoginWithCustomEndpointsThenBehaviorMatchesNamespace() throws Exception {
+		this.spring.register(FormLoginCustomConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
+
+		this.mvc.perform(post("/authentication/login/process").with(csrf()))
+				.andExpect(redirectedUrl("/authentication/login?failed"));
+
+		this.mvc.perform(post("/authentication/login/process").param("username", "user").param("password", "password")
+				.with(csrf())).andExpect(redirectedUrl("/default"));
+	}
+
+	@Test
+	public void formLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
+		this.spring.register(FormLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
+
+		this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure"));
+		verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
+
+		this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
+				.andExpect(redirectedUrl("/custom/targetUrl"));
+	}
+
+	private  T verifyBean(Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanClass));
+	}
+
 	@EnableWebSecurity
 	static class FormLoginConfig extends WebSecurityConfigurerAdapter {
 
@@ -92,19 +122,6 @@ public class NamespaceHttpFormLoginTests {
 
 	}
 
-	@Test
-	public void formLoginWithCustomEndpointsThenBehaviorMatchesNamespace() throws Exception {
-		this.spring.register(FormLoginCustomConfig.class, UserDetailsServiceConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
-
-		this.mvc.perform(post("/authentication/login/process").with(csrf()))
-				.andExpect(redirectedUrl("/authentication/login?failed"));
-
-		this.mvc.perform(post("/authentication/login/process").param("username", "user").param("password", "password")
-				.with(csrf())).andExpect(redirectedUrl("/default"));
-	}
-
 	@EnableWebSecurity
 	static class FormLoginCustomConfig extends WebSecurityConfigurerAdapter {
 
@@ -128,19 +145,6 @@ public class NamespaceHttpFormLoginTests {
 
 	}
 
-	@Test
-	public void formLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
-		this.spring.register(FormLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
-
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
-
-		this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure"));
-		verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
-
-		this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
-				.andExpect(redirectedUrl("/custom/targetUrl"));
-	}
-
 	@EnableWebSecurity
 	static class FormLoginCustomRefsConfig extends WebSecurityConfigurerAdapter {
 
@@ -186,8 +190,4 @@ public class NamespaceHttpFormLoginTests {
 
 	}
 
-	private  T verifyBean(Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanClass));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java
index 7ffd4c2dc7..403791c13e 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java
@@ -73,19 +73,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/").secure(true)).andExpect(includesDefaults());
 	}
 
-	@EnableWebSecurity
-	static class HeadersDefaultConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void secureRequestWhenCacheControlOnlyThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(HeadersCacheControlConfig.class).autowire();
@@ -93,21 +80,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/").secure(true)).andExpect(includes("Cache-Control", "Expires", "Pragma"));
 	}
 
-	@EnableWebSecurity
-	static class HeadersCacheControlConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.cacheControl();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void secureRequestWhenHstsOnlyThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(HstsConfig.class).autowire();
@@ -115,21 +87,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/").secure(true)).andExpect(includes("Strict-Transport-Security"));
 	}
 
-	@EnableWebSecurity
-	static class HstsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.httpStrictTransportSecurity();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenHstsCustomThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(HstsCustomConfig.class).autowire();
@@ -138,25 +95,6 @@ public class NamespaceHttpHeadersTests {
 				.andExpect(includes(Collections.singletonMap("Strict-Transport-Security", "max-age=15768000")));
 	}
 
-	@EnableWebSecurity
-	static class HstsCustomConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					// hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains
-					.defaultsDisabled()
-					.httpStrictTransportSecurity()
-						.requestMatcher(AnyRequestMatcher.INSTANCE)
-						.maxAgeInSeconds(15768000)
-						.includeSubDomains(false);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenFrameOptionsSameOriginThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(FrameOptionsSameOriginConfig.class).autowire();
@@ -164,26 +102,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/")).andExpect(includes(Collections.singletonMap("X-Frame-Options", "SAMEORIGIN")));
 	}
 
-	@EnableWebSecurity
-	static class FrameOptionsSameOriginConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					// frame-options@policy=SAMEORIGIN
-					.defaultsDisabled()
-					.frameOptions()
-						.sameOrigin();
-			// @formatter:on
-		}
-
-	}
-
-	// frame-options@strategy, frame-options@value, frame-options@parameter are not
-	// provided instead use frame-options@ref
-
 	@Test
 	public void requestWhenFrameOptionsAllowFromThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(FrameOptionsAllowFromConfig.class).autowire();
@@ -192,23 +110,6 @@ public class NamespaceHttpHeadersTests {
 				.andExpect(includes(Collections.singletonMap("X-Frame-Options", "ALLOW-FROM https://example.com")));
 	}
 
-	@EnableWebSecurity
-	static class FrameOptionsAllowFromConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					// frame-options@ref
-					.defaultsDisabled()
-					.addHeaderWriter(new XFrameOptionsHeaderWriter(
-							new StaticAllowFromStrategy(URI.create("https://example.com"))));
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenXssOnlyThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(XssProtectionConfig.class).autowire();
@@ -216,22 +117,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/")).andExpect(includes("X-XSS-Protection"));
 	}
 
-	@EnableWebSecurity
-	static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					// xss-protection
-					.defaultsDisabled()
-					.xssProtection();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenXssCustomThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(XssProtectionCustomConfig.class).autowire();
@@ -239,24 +124,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/")).andExpect(includes(Collections.singletonMap("X-XSS-Protection", "1")));
 	}
 
-	@EnableWebSecurity
-	static class XssProtectionCustomConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					// xss-protection@enabled and xss-protection@block
-					.defaultsDisabled()
-					.xssProtection()
-						.xssProtectionEnabled(true)
-						.block(false);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenXContentTypeOptionsOnlyThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(ContentTypeOptionsConfig.class).autowire();
@@ -264,24 +131,6 @@ public class NamespaceHttpHeadersTests {
 		this.mvc.perform(get("/")).andExpect(includes("X-Content-Type-Options"));
 	}
 
-	@EnableWebSecurity
-	static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					// content-type-options
-					.defaultsDisabled()
-					.contentTypeOptions();
-			// @formatter:on
-		}
-
-	}
-
-	// header@name / header@value are not provided instead use header@ref
-
 	@Test
 	public void requestWhenCustomHeaderOnlyThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(HeaderRefConfig.class).autowire();
@@ -290,21 +139,6 @@ public class NamespaceHttpHeadersTests {
 				.andExpect(includes(Collections.singletonMap("customHeaderName", "customHeaderValue")));
 	}
 
-	@EnableWebSecurity
-	static class HeaderRefConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.headers()
-					.defaultsDisabled()
-					.addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"));
-			// @formatter:on
-		}
-
-	}
-
 	private static ResultMatcher includesDefaults() {
 		return includes(defaultHeaders);
 	}
@@ -326,4 +160,165 @@ public class NamespaceHttpHeadersTests {
 		};
 	}
 
+	@EnableWebSecurity
+	static class HeadersDefaultConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HeadersCacheControlConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.cacheControl();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HstsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.httpStrictTransportSecurity();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HstsCustomConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					// hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains
+					.defaultsDisabled()
+					.httpStrictTransportSecurity()
+						.requestMatcher(AnyRequestMatcher.INSTANCE)
+						.maxAgeInSeconds(15768000)
+						.includeSubDomains(false);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class FrameOptionsSameOriginConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					// frame-options@policy=SAMEORIGIN
+					.defaultsDisabled()
+					.frameOptions()
+						.sameOrigin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class FrameOptionsAllowFromConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					// frame-options@ref
+					.defaultsDisabled()
+					.addHeaderWriter(new XFrameOptionsHeaderWriter(
+							new StaticAllowFromStrategy(URI.create("https://example.com"))));
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					// xss-protection
+					.defaultsDisabled()
+					.xssProtection();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class XssProtectionCustomConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					// xss-protection@enabled and xss-protection@block
+					.defaultsDisabled()
+					.xssProtection()
+						.xssProtectionEnabled(true)
+						.block(false);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					// content-type-options
+					.defaultsDisabled()
+					.contentTypeOptions();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HeaderRefConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers()
+					.defaultsDisabled()
+					.addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"));
+			// @formatter:on
+		}
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java
index 078c69053d..08dcf7f70c 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java
@@ -100,6 +100,10 @@ public class NamespaceHttpInterceptUrlTests {
 		this.mvc.perform(get("https://localhost/user")).andExpect(redirectedUrl("http://localhost/user"));
 	}
 
+	private static Authentication user(String role) {
+		return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.createAuthorityList(role));
+	}
+
 	@EnableWebSecurity
 	static class HttpInterceptUrlConfig extends WebSecurityConfigurerAdapter {
 
@@ -173,8 +177,4 @@ public class NamespaceHttpInterceptUrlTests {
 
 	}
 
-	private static Authentication user(String role) {
-		return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.createAuthorityList(role));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java
index d62421f8fc..7cc239f3ab 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java
@@ -73,23 +73,6 @@ public class NamespaceHttpJeeTests {
 		})).andExpect(status().isOk()).andExpect(content().string("ROLE_admin,ROLE_user"));
 	}
 
-	@EnableWebSecurity
-	public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("user")
-					.and()
-				.jee()
-					.mappableRoles("user", "admin");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenCustomAuthenticatedUserDetailsServiceThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(JeeUserServiceRefConfig.class, BaseController.class).autowire();
@@ -108,6 +91,31 @@ public class NamespaceHttpJeeTests {
 		verifyBean(AuthenticationUserDetailsService.class).loadUserDetails(any());
 	}
 
+	private  T bean(Class beanClass) {
+		return this.spring.getContext().getBean(beanClass);
+	}
+
+	private  T verifyBean(Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanClass));
+	}
+
+	@EnableWebSecurity
+	public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("user")
+					.and()
+				.jee()
+					.mappableRoles("user", "admin");
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	public static class JeeUserServiceRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -149,12 +157,4 @@ public class NamespaceHttpJeeTests {
 
 	}
 
-	private  T bean(Class beanClass) {
-		return this.spring.getContext().getBean(beanClass);
-	}
-
-	private  T verifyBean(Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanClass));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
index 407499bfb1..5d56d6c05c 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
@@ -76,15 +76,6 @@ public class NamespaceHttpLogoutTests {
 				.andExpect(redirectedUrl("/login?logout")).andExpect(noCookies()).andExpect(session(Objects::isNull));
 	}
 
-	@EnableWebSecurity
-	static class HttpLogoutConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) {
-		}
-
-	}
-
 	@Test
 	@WithMockUser
 	public void logoutWhenDisabledInLambdaThenRespondsWithNotFound() throws Exception {
@@ -93,16 +84,6 @@ public class NamespaceHttpLogoutTests {
 		this.mvc.perform(post("/logout").with(csrf()).with(user("user"))).andExpect(status().isNotFound());
 	}
 
-	@EnableWebSecurity
-	static class HttpLogoutDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			http.logout(AbstractHttpConfigurer::disable);
-		}
-
-	}
-
 	/**
 	 * http/logout custom
 	 */
@@ -117,6 +98,73 @@ public class NamespaceHttpLogoutTests {
 				.andExpect(cookie().maxAge("remove", 0)).andExpect(session(Objects::nonNull));
 	}
 
+	@Test
+	@WithMockUser
+	public void logoutWhenUsingVariousCustomizationsInLambdaThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomHttpLogoutInLambdaConfig.class).autowire();
+
+		this.mvc.perform(post("/custom-logout").with(csrf())).andExpect(authenticated(false))
+				.andExpect(redirectedUrl("/logout-success"))
+				.andExpect(result -> assertThat(result.getResponse().getCookies()).hasSize(1))
+				.andExpect(cookie().maxAge("remove", 0)).andExpect(session(Objects::nonNull));
+	}
+
+	/**
+	 * http/logout@success-handler-ref
+	 */
+	@Test
+	@WithMockUser
+	public void logoutWhenUsingSuccessHandlerRefThenMatchesNamespace() throws Exception {
+		this.spring.register(SuccessHandlerRefHttpLogoutConfig.class).autowire();
+
+		this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
+				.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies())
+				.andExpect(session(Objects::isNull));
+	}
+
+	@Test
+	@WithMockUser
+	public void logoutWhenUsingSuccessHandlerRefInLambdaThenMatchesNamespace() throws Exception {
+		this.spring.register(SuccessHandlerRefHttpLogoutInLambdaConfig.class).autowire();
+
+		this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
+				.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies())
+				.andExpect(session(Objects::isNull));
+	}
+
+	ResultMatcher authenticated(boolean authenticated) {
+		return result -> assertThat(Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
+				.map(Authentication::isAuthenticated).orElse(false)).isEqualTo(authenticated);
+	}
+
+	ResultMatcher noCookies() {
+		return result -> assertThat(result.getResponse().getCookies()).isEmpty();
+	}
+
+	ResultMatcher session(Predicate sessionPredicate) {
+		return result -> assertThat(result.getRequest().getSession(false))
+				.is(new Condition<>(sessionPredicate, "sessionPredicate failed"));
+	}
+
+	@EnableWebSecurity
+	static class HttpLogoutConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) {
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class HttpLogoutDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http.logout(AbstractHttpConfigurer::disable);
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class CustomHttpLogoutConfig extends WebSecurityConfigurerAdapter {
 
@@ -134,17 +182,6 @@ public class NamespaceHttpLogoutTests {
 
 	}
 
-	@Test
-	@WithMockUser
-	public void logoutWhenUsingVariousCustomizationsInLambdaThenMatchesNamespace() throws Exception {
-		this.spring.register(CustomHttpLogoutInLambdaConfig.class).autowire();
-
-		this.mvc.perform(post("/custom-logout").with(csrf())).andExpect(authenticated(false))
-				.andExpect(redirectedUrl("/logout-success"))
-				.andExpect(result -> assertThat(result.getResponse().getCookies()).hasSize(1))
-				.andExpect(cookie().maxAge("remove", 0)).andExpect(session(Objects::nonNull));
-	}
-
 	@EnableWebSecurity
 	static class CustomHttpLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -163,19 +200,6 @@ public class NamespaceHttpLogoutTests {
 
 	}
 
-	/**
-	 * http/logout@success-handler-ref
-	 */
-	@Test
-	@WithMockUser
-	public void logoutWhenUsingSuccessHandlerRefThenMatchesNamespace() throws Exception {
-		this.spring.register(SuccessHandlerRefHttpLogoutConfig.class).autowire();
-
-		this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
-				.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies())
-				.andExpect(session(Objects::isNull));
-	}
-
 	@EnableWebSecurity
 	static class SuccessHandlerRefHttpLogoutConfig extends WebSecurityConfigurerAdapter {
 
@@ -192,16 +216,6 @@ public class NamespaceHttpLogoutTests {
 
 	}
 
-	@Test
-	@WithMockUser
-	public void logoutWhenUsingSuccessHandlerRefInLambdaThenMatchesNamespace() throws Exception {
-		this.spring.register(SuccessHandlerRefHttpLogoutInLambdaConfig.class).autowire();
-
-		this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
-				.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies())
-				.andExpect(session(Objects::isNull));
-	}
-
 	@EnableWebSecurity
 	static class SuccessHandlerRefHttpLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -218,18 +232,4 @@ public class NamespaceHttpLogoutTests {
 
 	}
 
-	ResultMatcher authenticated(boolean authenticated) {
-		return result -> assertThat(Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
-				.map(Authentication::isAuthenticated).orElse(false)).isEqualTo(authenticated);
-	}
-
-	ResultMatcher noCookies() {
-		return result -> assertThat(result.getResponse().getCookies()).isEmpty();
-	}
-
-	ResultMatcher session(Predicate sessionPredicate) {
-		return result -> assertThat(result.getRequest().getSession(false))
-				.is(new Condition<>(sessionPredicate, "sessionPredicate failed"));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpOpenIDLoginTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpOpenIDLoginTests.java
index 1142c5d8f5..81133d4084 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpOpenIDLoginTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpOpenIDLoginTests.java
@@ -92,24 +92,6 @@ public class NamespaceHttpOpenIDLoginTests {
 		this.mvc.perform(post("/login/openid").with(csrf())).andExpect(redirectedUrl("/login?error"));
 	}
 
-	@Configuration
-	@EnableWebSecurity
-	static class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.openidLogin()
-					.permitAll();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void openidLoginWhenAttributeExchangeConfiguredThenFetchAttributesMatchAttributeList() throws Exception {
 		OpenIDLoginAttributeExchangeConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
@@ -148,6 +130,59 @@ public class NamespaceHttpOpenIDLoginTests {
 		}
 	}
 
+	@Test
+	public void openidLoginWhenUsingCustomEndpointsThenMatchesNamespace() throws Exception {
+		this.spring.register(OpenIDLoginCustomConfig.class).autowire();
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
+		this.mvc.perform(post("/authentication/login/process").with(csrf()))
+				.andExpect(redirectedUrl("/authentication/login?failed"));
+	}
+
+	@Test
+	public void openidLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
+		OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS,
+				"identityUrl", "message", Arrays.asList(new OpenIDAttribute("name", "type")));
+
+		OpenIDLoginCustomRefsConfig.AUDS = mock(AuthenticationUserDetailsService.class);
+		when(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class)))
+				.thenReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
+		OpenIDLoginCustomRefsConfig.ADS = spy(new WebAuthenticationDetailsSource());
+		OpenIDLoginCustomRefsConfig.CONSUMER = mock(OpenIDConsumer.class);
+
+		this.spring.register(OpenIDLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		when(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class)))
+				.thenThrow(new AuthenticationServiceException("boom"));
+		this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity"))
+				.andExpect(redirectedUrl("/custom/failure"));
+		reset(OpenIDLoginCustomRefsConfig.CONSUMER);
+
+		when(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))).thenReturn(token);
+		this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity"))
+				.andExpect(redirectedUrl("/custom/targetUrl"));
+
+		verify(OpenIDLoginCustomRefsConfig.AUDS).loadUserDetails(any(Authentication.class));
+		verify(OpenIDLoginCustomRefsConfig.ADS).buildDetails(any(Object.class));
+	}
+
+	@Configuration
+	@EnableWebSecurity
+	static class OpenIDLoginConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.openidLogin()
+					.permitAll();
+			// @formatter:on
+		}
+
+	}
+
 	@Configuration
 	@EnableWebSecurity
 	static class OpenIDLoginAttributeExchangeConfig extends WebSecurityConfigurerAdapter {
@@ -194,14 +229,6 @@ public class NamespaceHttpOpenIDLoginTests {
 
 	}
 
-	@Test
-	public void openidLoginWhenUsingCustomEndpointsThenMatchesNamespace() throws Exception {
-		this.spring.register(OpenIDLoginCustomConfig.class).autowire();
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
-		this.mvc.perform(post("/authentication/login/process").with(csrf()))
-				.andExpect(redirectedUrl("/authentication/login?failed"));
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class OpenIDLoginCustomConfig extends WebSecurityConfigurerAdapter {
@@ -225,33 +252,6 @@ public class NamespaceHttpOpenIDLoginTests {
 
 	}
 
-	@Test
-	public void openidLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
-		OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS,
-				"identityUrl", "message", Arrays.asList(new OpenIDAttribute("name", "type")));
-
-		OpenIDLoginCustomRefsConfig.AUDS = mock(AuthenticationUserDetailsService.class);
-		when(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class)))
-				.thenReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
-		OpenIDLoginCustomRefsConfig.ADS = spy(new WebAuthenticationDetailsSource());
-		OpenIDLoginCustomRefsConfig.CONSUMER = mock(OpenIDConsumer.class);
-
-		this.spring.register(OpenIDLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
-
-		when(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class)))
-				.thenThrow(new AuthenticationServiceException("boom"));
-		this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity"))
-				.andExpect(redirectedUrl("/custom/failure"));
-		reset(OpenIDLoginCustomRefsConfig.CONSUMER);
-
-		when(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))).thenReturn(token);
-		this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity"))
-				.andExpect(redirectedUrl("/custom/targetUrl"));
-
-		verify(OpenIDLoginCustomRefsConfig.AUDS).loadUserDetails(any(Authentication.class));
-		verify(OpenIDLoginCustomRefsConfig.ADS).buildDetails(any(Object.class));
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class OpenIDLoginCustomRefsConfig extends WebSecurityConfigurerAdapter {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java
index dd6f0a250a..6969c377e1 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java
@@ -64,6 +64,21 @@ public class NamespaceHttpRequestCacheTests {
 		verifyBean(RequestCache.class).saveRequest(any(HttpServletRequest.class), any(HttpServletResponse.class));
 	}
 
+	@Test
+	public void requestWhenDefaultConfigurationThenUsesHttpSessionRequestCache() throws Exception {
+		this.spring.register(DefaultRequestCacheRefConfig.class).autowire();
+
+		MvcResult result = this.mvc.perform(get("/")).andExpect(status().isForbidden()).andReturn();
+
+		HttpSession session = result.getRequest().getSession(false);
+		assertThat(session).isNotNull();
+		assertThat(session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")).isNotNull();
+	}
+
+	private  T verifyBean(Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanClass));
+	}
+
 	@EnableWebSecurity
 	static class RequestCacheRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -96,17 +111,6 @@ public class NamespaceHttpRequestCacheTests {
 
 	}
 
-	@Test
-	public void requestWhenDefaultConfigurationThenUsesHttpSessionRequestCache() throws Exception {
-		this.spring.register(DefaultRequestCacheRefConfig.class).autowire();
-
-		MvcResult result = this.mvc.perform(get("/")).andExpect(status().isForbidden()).andReturn();
-
-		HttpSession session = result.getRequest().getSession(false);
-		assertThat(session).isNotNull();
-		assertThat(session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")).isNotNull();
-	}
-
 	@EnableWebSecurity
 	static class DefaultRequestCacheRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -131,8 +135,4 @@ public class NamespaceHttpRequestCacheTests {
 
 	}
 
-	private  T verifyBean(Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanClass));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
index d5729357b6..76e422ac91 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
@@ -65,6 +65,40 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
 				.andExpect(forwardedUrl("/AccessDeniedPageConfig"));
 	}
 
+	@Test
+	public void requestWhenCustomAccessDeniedPageInLambdaThenForwardedToCustomPage() throws Exception {
+		this.spring.register(AccessDeniedPageInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/").with(authentication(user()))).andExpect(status().isForbidden())
+				.andExpect(forwardedUrl("/AccessDeniedPageConfig"));
+	}
+
+	@Test
+	public void requestWhenCustomAccessDeniedHandlerThenBehaviorMatchesNamespace() throws Exception {
+		this.spring.register(AccessDeniedHandlerRefConfig.class).autowire();
+		this.mvc.perform(get("/").with(authentication(user())));
+		verifyBean(AccessDeniedHandler.class).handle(any(HttpServletRequest.class), any(HttpServletResponse.class),
+				any(AccessDeniedException.class));
+	}
+
+	@Test
+	public void requestWhenCustomAccessDeniedHandlerInLambdaThenBehaviorMatchesNamespace() throws Exception {
+		this.spring.register(AccessDeniedHandlerRefInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/").with(authentication(user())));
+
+		verify(AccessDeniedHandlerRefInLambdaConfig.accessDeniedHandler).handle(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any(AccessDeniedException.class));
+	}
+
+	private static Authentication user() {
+		return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.NO_AUTHORITIES);
+	}
+
+	private  T verifyBean(Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanClass));
+	}
+
 	@EnableWebSecurity
 	static class AccessDeniedPageConfig extends WebSecurityConfigurerAdapter {
 
@@ -82,18 +116,6 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
 
 	}
 
-	private static Authentication user() {
-		return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.NO_AUTHORITIES);
-	}
-
-	@Test
-	public void requestWhenCustomAccessDeniedPageInLambdaThenForwardedToCustomPage() throws Exception {
-		this.spring.register(AccessDeniedPageInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/").with(authentication(user()))).andExpect(status().isForbidden())
-				.andExpect(forwardedUrl("/AccessDeniedPageConfig"));
-	}
-
 	@EnableWebSecurity
 	static class AccessDeniedPageInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -113,14 +135,6 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
 
 	}
 
-	@Test
-	public void requestWhenCustomAccessDeniedHandlerThenBehaviorMatchesNamespace() throws Exception {
-		this.spring.register(AccessDeniedHandlerRefConfig.class).autowire();
-		this.mvc.perform(get("/").with(authentication(user())));
-		verifyBean(AccessDeniedHandler.class).handle(any(HttpServletRequest.class), any(HttpServletResponse.class),
-				any(AccessDeniedException.class));
-	}
-
 	@EnableWebSecurity
 	static class AccessDeniedHandlerRefConfig extends WebSecurityConfigurerAdapter {
 
@@ -143,16 +157,6 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
 
 	}
 
-	@Test
-	public void requestWhenCustomAccessDeniedHandlerInLambdaThenBehaviorMatchesNamespace() throws Exception {
-		this.spring.register(AccessDeniedHandlerRefInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/").with(authentication(user())));
-
-		verify(AccessDeniedHandlerRefInLambdaConfig.accessDeniedHandler).handle(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any(AccessDeniedException.class));
-	}
-
 	@EnableWebSecurity
 	static class AccessDeniedHandlerRefInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -179,8 +183,4 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
 
 	}
 
-	private  T verifyBean(Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanClass));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java
index b6a997ba33..74cc76cd4d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java
@@ -77,6 +77,58 @@ public class NamespaceHttpX509Tests {
 		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod"));
 	}
 
+	@Test
+	public void x509AuthenticationWhenHasCustomAuthenticationDetailsSourceThenMatchesNamespace() throws Exception {
+		this.spring.register(AuthenticationDetailsSourceRefConfig.class, X509Controller.class).autowire();
+
+		X509Certificate certificate = loadCert("rod.cer");
+		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod"));
+
+		verifyBean(AuthenticationDetailsSource.class).buildDetails(any());
+	}
+
+	@Test
+	public void x509AuthenticationWhenHasSubjectPrincipalRegexThenMatchesNamespace() throws Exception {
+		this.spring.register(SubjectPrincipalRegexConfig.class, X509Controller.class).autowire();
+		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod"));
+	}
+
+	@Test
+	public void x509AuthenticationWhenHasCustomPrincipalExtractorThenMatchesNamespace() throws Exception {
+		this.spring.register(CustomPrincipalExtractorConfig.class, X509Controller.class).autowire();
+		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod@example.com"));
+	}
+
+	@Test
+	public void x509AuthenticationWhenHasCustomUserDetailsServiceThenMatchesNamespace() throws Exception {
+		this.spring.register(UserDetailsServiceRefConfig.class, X509Controller.class).autowire();
+		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("customuser"));
+	}
+
+	@Test
+	public void x509AuthenticationWhenHasCustomAuthenticationUserDetailsServiceThenMatchesNamespace() throws Exception {
+		this.spring.register(AuthenticationUserDetailsServiceConfig.class, X509Controller.class).autowire();
+		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("customuser"));
+	}
+
+	 T loadCert(String location) {
+		try (InputStream is = new ClassPathResource(location).getInputStream()) {
+			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+			return (T) certFactory.generateCertificate(is);
+		}
+		catch (Exception e) {
+			throw new IllegalArgumentException(e);
+		}
+	}
+
+	 T verifyBean(Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanClass));
+	}
+
 	@EnableWebSecurity
 	@EnableWebMvc
 	public static class X509Config extends WebSecurityConfigurerAdapter {
@@ -103,16 +155,6 @@ public class NamespaceHttpX509Tests {
 
 	}
 
-	@Test
-	public void x509AuthenticationWhenHasCustomAuthenticationDetailsSourceThenMatchesNamespace() throws Exception {
-		this.spring.register(AuthenticationDetailsSourceRefConfig.class, X509Controller.class).autowire();
-
-		X509Certificate certificate = loadCert("rod.cer");
-		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod"));
-
-		verifyBean(AuthenticationDetailsSource.class).buildDetails(any());
-	}
-
 	@EnableWebSecurity
 	@EnableWebMvc
 	static class AuthenticationDetailsSourceRefConfig extends WebSecurityConfigurerAdapter {
@@ -146,13 +188,6 @@ public class NamespaceHttpX509Tests {
 
 	}
 
-	@Test
-	public void x509AuthenticationWhenHasSubjectPrincipalRegexThenMatchesNamespace() throws Exception {
-		this.spring.register(SubjectPrincipalRegexConfig.class, X509Controller.class).autowire();
-		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
-		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod"));
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	public static class SubjectPrincipalRegexConfig extends WebSecurityConfigurerAdapter {
@@ -180,13 +215,6 @@ public class NamespaceHttpX509Tests {
 
 	}
 
-	@Test
-	public void x509AuthenticationWhenHasCustomPrincipalExtractorThenMatchesNamespace() throws Exception {
-		this.spring.register(CustomPrincipalExtractorConfig.class, X509Controller.class).autowire();
-		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
-		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("rod@example.com"));
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	public static class CustomPrincipalExtractorConfig extends WebSecurityConfigurerAdapter {
@@ -223,13 +251,6 @@ public class NamespaceHttpX509Tests {
 
 	}
 
-	@Test
-	public void x509AuthenticationWhenHasCustomUserDetailsServiceThenMatchesNamespace() throws Exception {
-		this.spring.register(UserDetailsServiceRefConfig.class, X509Controller.class).autowire();
-		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
-		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("customuser"));
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	public static class UserDetailsServiceRefConfig extends WebSecurityConfigurerAdapter {
@@ -257,13 +278,6 @@ public class NamespaceHttpX509Tests {
 
 	}
 
-	@Test
-	public void x509AuthenticationWhenHasCustomAuthenticationUserDetailsServiceThenMatchesNamespace() throws Exception {
-		this.spring.register(AuthenticationUserDetailsServiceConfig.class, X509Controller.class).autowire();
-		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
-		this.mvc.perform(get("/whoami").with(x509(certificate))).andExpect(content().string("customuser"));
-	}
-
 	@EnableWebMvc
 	@EnableWebSecurity
 	public static class AuthenticationUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@@ -297,18 +311,4 @@ public class NamespaceHttpX509Tests {
 
 	}
 
-	 T loadCert(String location) {
-		try (InputStream is = new ClassPathResource(location).getInputStream()) {
-			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-			return (T) certFactory.generateCertificate(is);
-		}
-		catch (Exception e) {
-			throw new IllegalArgumentException(e);
-		}
-	}
-
-	 T verifyBean(Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanClass));
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java
index aeac564a92..548c700491 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java
@@ -98,6 +98,160 @@ public class NamespaceRememberMeTests {
 				.andExpect(redirectedUrl("http://localhost/login")).andReturn();
 	}
 
+	// SEC-3170 - RememberMeService implementations should not have to also implement
+	// LogoutHandler
+	@Test
+	public void logoutWhenCustomRememberMeServicesDeclaredThenUses() throws Exception {
+		RememberMeServicesRefConfig.REMEMBER_ME_SERVICES = mock(RememberMeServicesWithoutLogoutHandler.class);
+		this.spring.register(RememberMeServicesRefConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+		verify(RememberMeServicesRefConfig.REMEMBER_ME_SERVICES).autoLogin(any(HttpServletRequest.class),
+				any(HttpServletResponse.class));
+
+		this.mvc.perform(post("/login").with(csrf()));
+		verify(RememberMeServicesRefConfig.REMEMBER_ME_SERVICES).loginFail(any(HttpServletRequest.class),
+				any(HttpServletResponse.class));
+	}
+
+	@Test
+	public void rememberMeLoginWhenAuthenticationSuccessHandlerDeclaredThenUses() throws Exception {
+		AuthSuccessConfig.SUCCESS_HANDLER = mock(AuthenticationSuccessHandler.class);
+		this.spring.register(AuthSuccessConfig.class).autowire();
+
+		MvcResult result = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn();
+
+		verifyZeroInteractions(AuthSuccessConfig.SUCCESS_HANDLER);
+
+		Cookie rememberMe = result.getResponse().getCookie("remember-me");
+		assertThat(rememberMe).isNotNull();
+		this.mvc.perform(get("/somewhere").cookie(rememberMe));
+
+		verify(AuthSuccessConfig.SUCCESS_HANDLER).onAuthenticationSuccess(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any(Authentication.class));
+	}
+
+	@Test
+	public void rememberMeLoginWhenKeyDeclaredThenMatchesNamespace() throws Exception {
+		this.spring.register(WithoutKeyConfig.class, KeyConfig.class, SecurityController.class).autowire();
+		Cookie withoutKey = this.mvc.perform(post("/without-key/login").with(rememberMeLogin()))
+				.andExpect(redirectedUrl("/")).andReturn().getResponse().getCookie("remember-me");
+
+		this.mvc.perform(get("/somewhere").cookie(withoutKey)).andExpect(status().isFound())
+				.andExpect(redirectedUrl("http://localhost/login"));
+
+		Cookie withKey = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
+				.getCookie("remember-me");
+		this.mvc.perform(get("/somewhere").cookie(withKey)).andExpect(status().isNotFound());
+	}
+
+	// http/remember-me@services-alias is not supported use standard aliasing instead
+	// (i.e. @Bean("alias"))
+
+	// http/remember-me@data-source-ref is not supported directly. Instead use
+	// http/remember-me@token-repository-ref example
+	@Test
+	public void rememberMeLoginWhenDeclaredTokenRepositoryThenMatchesNamespace() throws Exception {
+		TokenRepositoryRefConfig.TOKEN_REPOSITORY = mock(PersistentTokenRepository.class);
+		this.spring.register(TokenRepositoryRefConfig.class).autowire();
+
+		this.mvc.perform(post("/login").with(rememberMeLogin()));
+
+		verify(TokenRepositoryRefConfig.TOKEN_REPOSITORY).createNewToken(any(PersistentRememberMeToken.class));
+	}
+
+	@Test
+	public void rememberMeLoginWhenTokenValidityDeclaredThenMatchesNamespace() throws Exception {
+		this.spring.register(TokenValiditySecondsConfig.class).autowire();
+		Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
+				.getCookie("remember-me");
+
+		assertThat(expiredRememberMe).extracting(Cookie::getMaxAge).isEqualTo(314);
+	}
+
+	@Test
+	public void rememberMeLoginWhenUsingDefaultsThenCookieMaxAgeMatchesNamespace() throws Exception {
+		this.spring.register(RememberMeConfig.class).autowire();
+		Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
+				.getCookie("remember-me");
+
+		assertThat(expiredRememberMe).extracting(Cookie::getMaxAge).isEqualTo(AbstractRememberMeServices.TWO_WEEKS_S);
+	}
+
+	@Test
+	public void rememberMeLoginWhenUsingSecureCookieThenMatchesNamespace() throws Exception {
+		this.spring.register(UseSecureCookieConfig.class).autowire();
+		Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
+				.getCookie("remember-me");
+
+		assertThat(secureCookie).extracting(Cookie::getSecure).isEqualTo(true);
+	}
+
+	@Test
+	public void rememberMeLoginWhenUsingDefaultsThenCookieSecurityMatchesNamespace() throws Exception {
+		this.spring.register(RememberMeConfig.class).autowire();
+		Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin()).secure(true)).andReturn()
+				.getResponse().getCookie("remember-me");
+
+		assertThat(secureCookie).extracting(Cookie::getSecure).isEqualTo(true);
+	}
+
+	@Test
+	public void rememberMeLoginWhenParameterSpecifiedThenMatchesNamespace() throws Exception {
+		this.spring.register(RememberMeParameterConfig.class).autowire();
+		Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin("rememberMe", true))).andReturn()
+				.getResponse().getCookie("remember-me");
+
+		assertThat(rememberMe).isNotNull();
+	}
+
+	// SEC-2880
+	@Test
+	public void rememberMeLoginWhenCookieNameDeclaredThenMatchesNamespace() throws Exception {
+		this.spring.register(RememberMeCookieNameConfig.class).autowire();
+		Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
+				.getCookie("rememberMe");
+
+		assertThat(rememberMe).isNotNull();
+	}
+
+	@Test
+	public void rememberMeLoginWhenGlobalUserDetailsServiceDeclaredThenMatchesNamespace() throws Exception {
+		DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE = mock(UserDetailsService.class);
+		this.spring.register(DefaultsUserDetailsServiceWithDaoConfig.class).autowire();
+
+		this.mvc.perform(post("/login").with(rememberMeLogin()));
+
+		verify(DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE).loadUserByUsername("user");
+	}
+
+	@Test
+	public void rememberMeLoginWhenUserDetailsServiceDeclaredThenMatchesNamespace() throws Exception {
+		UserServiceRefConfig.USERDETAILS_SERVICE = mock(UserDetailsService.class);
+		this.spring.register(UserServiceRefConfig.class).autowire();
+
+		when(UserServiceRefConfig.USERDETAILS_SERVICE.loadUserByUsername("user"))
+				.thenReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
+
+		this.mvc.perform(post("/login").with(rememberMeLogin()));
+
+		verify(UserServiceRefConfig.USERDETAILS_SERVICE).loadUserByUsername("user");
+	}
+
+	static RequestPostProcessor rememberMeLogin() {
+		return rememberMeLogin("remember-me", true);
+	}
+
+	static RequestPostProcessor rememberMeLogin(String parameterName, boolean parameterValue) {
+		return request -> {
+			csrf().postProcessRequest(request);
+			request.setParameter("username", "user");
+			request.setParameter("password", "password");
+			request.setParameter(parameterName, String.valueOf(parameterValue));
+			return request;
+		};
+	}
+
 	@Configuration
 	@EnableWebSecurity
 	static class RememberMeConfig extends UsersConfig {
@@ -117,22 +271,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	// SEC-3170 - RememberMeService implementations should not have to also implement
-	// LogoutHandler
-	@Test
-	public void logoutWhenCustomRememberMeServicesDeclaredThenUses() throws Exception {
-		RememberMeServicesRefConfig.REMEMBER_ME_SERVICES = mock(RememberMeServicesWithoutLogoutHandler.class);
-		this.spring.register(RememberMeServicesRefConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-		verify(RememberMeServicesRefConfig.REMEMBER_ME_SERVICES).autoLogin(any(HttpServletRequest.class),
-				any(HttpServletResponse.class));
-
-		this.mvc.perform(post("/login").with(csrf()));
-		verify(RememberMeServicesRefConfig.REMEMBER_ME_SERVICES).loginFail(any(HttpServletRequest.class),
-				any(HttpServletResponse.class));
-	}
-
 	interface RememberMeServicesWithoutLogoutHandler extends RememberMeServices {
 
 	}
@@ -156,23 +294,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenAuthenticationSuccessHandlerDeclaredThenUses() throws Exception {
-		AuthSuccessConfig.SUCCESS_HANDLER = mock(AuthenticationSuccessHandler.class);
-		this.spring.register(AuthSuccessConfig.class).autowire();
-
-		MvcResult result = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn();
-
-		verifyZeroInteractions(AuthSuccessConfig.SUCCESS_HANDLER);
-
-		Cookie rememberMe = result.getResponse().getCookie("remember-me");
-		assertThat(rememberMe).isNotNull();
-		this.mvc.perform(get("/somewhere").cookie(rememberMe));
-
-		verify(AuthSuccessConfig.SUCCESS_HANDLER).onAuthenticationSuccess(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any(Authentication.class));
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class AuthSuccessConfig extends UsersConfig {
@@ -192,20 +313,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenKeyDeclaredThenMatchesNamespace() throws Exception {
-		this.spring.register(WithoutKeyConfig.class, KeyConfig.class, SecurityController.class).autowire();
-		Cookie withoutKey = this.mvc.perform(post("/without-key/login").with(rememberMeLogin()))
-				.andExpect(redirectedUrl("/")).andReturn().getResponse().getCookie("remember-me");
-
-		this.mvc.perform(get("/somewhere").cookie(withoutKey)).andExpect(status().isFound())
-				.andExpect(redirectedUrl("http://localhost/login"));
-
-		Cookie withKey = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
-				.getCookie("remember-me");
-		this.mvc.perform(get("/somewhere").cookie(withKey)).andExpect(status().isNotFound());
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	@Order(0)
@@ -245,21 +352,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	// http/remember-me@services-alias is not supported use standard aliasing instead
-	// (i.e. @Bean("alias"))
-
-	// http/remember-me@data-source-ref is not supported directly. Instead use
-	// http/remember-me@token-repository-ref example
-	@Test
-	public void rememberMeLoginWhenDeclaredTokenRepositoryThenMatchesNamespace() throws Exception {
-		TokenRepositoryRefConfig.TOKEN_REPOSITORY = mock(PersistentTokenRepository.class);
-		this.spring.register(TokenRepositoryRefConfig.class).autowire();
-
-		this.mvc.perform(post("/login").with(rememberMeLogin()));
-
-		verify(TokenRepositoryRefConfig.TOKEN_REPOSITORY).createNewToken(any(PersistentRememberMeToken.class));
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class TokenRepositoryRefConfig extends UsersConfig {
@@ -282,15 +374,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenTokenValidityDeclaredThenMatchesNamespace() throws Exception {
-		this.spring.register(TokenValiditySecondsConfig.class).autowire();
-		Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
-				.getCookie("remember-me");
-
-		assertThat(expiredRememberMe).extracting(Cookie::getMaxAge).isEqualTo(314);
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class TokenValiditySecondsConfig extends UsersConfig {
@@ -311,24 +394,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenUsingDefaultsThenCookieMaxAgeMatchesNamespace() throws Exception {
-		this.spring.register(RememberMeConfig.class).autowire();
-		Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
-				.getCookie("remember-me");
-
-		assertThat(expiredRememberMe).extracting(Cookie::getMaxAge).isEqualTo(AbstractRememberMeServices.TWO_WEEKS_S);
-	}
-
-	@Test
-	public void rememberMeLoginWhenUsingSecureCookieThenMatchesNamespace() throws Exception {
-		this.spring.register(UseSecureCookieConfig.class).autowire();
-		Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
-				.getCookie("remember-me");
-
-		assertThat(secureCookie).extracting(Cookie::getSecure).isEqualTo(true);
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class UseSecureCookieConfig extends UsersConfig {
@@ -346,24 +411,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenUsingDefaultsThenCookieSecurityMatchesNamespace() throws Exception {
-		this.spring.register(RememberMeConfig.class).autowire();
-		Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin()).secure(true)).andReturn()
-				.getResponse().getCookie("remember-me");
-
-		assertThat(secureCookie).extracting(Cookie::getSecure).isEqualTo(true);
-	}
-
-	@Test
-	public void rememberMeLoginWhenParameterSpecifiedThenMatchesNamespace() throws Exception {
-		this.spring.register(RememberMeParameterConfig.class).autowire();
-		Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin("rememberMe", true))).andReturn()
-				.getResponse().getCookie("remember-me");
-
-		assertThat(rememberMe).isNotNull();
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class RememberMeParameterConfig extends UsersConfig {
@@ -381,17 +428,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	// SEC-2880
-
-	@Test
-	public void rememberMeLoginWhenCookieNameDeclaredThenMatchesNamespace() throws Exception {
-		this.spring.register(RememberMeCookieNameConfig.class).autowire();
-		Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
-				.getCookie("rememberMe");
-
-		assertThat(rememberMe).isNotNull();
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class RememberMeCookieNameConfig extends UsersConfig {
@@ -409,16 +445,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenGlobalUserDetailsServiceDeclaredThenMatchesNamespace() throws Exception {
-		DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE = mock(UserDetailsService.class);
-		this.spring.register(DefaultsUserDetailsServiceWithDaoConfig.class).autowire();
-
-		this.mvc.perform(post("/login").with(rememberMeLogin()));
-
-		verify(DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE).loadUserByUsername("user");
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	static class DefaultsUserDetailsServiceWithDaoConfig extends WebSecurityConfigurerAdapter {
@@ -445,19 +471,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	@Test
-	public void rememberMeLoginWhenUserDetailsServiceDeclaredThenMatchesNamespace() throws Exception {
-		UserServiceRefConfig.USERDETAILS_SERVICE = mock(UserDetailsService.class);
-		this.spring.register(UserServiceRefConfig.class).autowire();
-
-		when(UserServiceRefConfig.USERDETAILS_SERVICE.loadUserByUsername("user"))
-				.thenReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
-
-		this.mvc.perform(post("/login").with(rememberMeLogin()));
-
-		verify(UserServiceRefConfig.USERDETAILS_SERVICE).loadUserByUsername("user");
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class UserServiceRefConfig extends UsersConfig {
@@ -477,20 +490,6 @@ public class NamespaceRememberMeTests {
 
 	}
 
-	static RequestPostProcessor rememberMeLogin() {
-		return rememberMeLogin("remember-me", true);
-	}
-
-	static RequestPostProcessor rememberMeLogin(String parameterName, boolean parameterValue) {
-		return request -> {
-			csrf().postProcessRequest(request);
-			request.setParameter("username", "user");
-			request.setParameter("password", "password");
-			request.setParameter(parameterName, String.valueOf(parameterValue));
-			return request;
-		};
-	}
-
 	static class UsersConfig extends WebSecurityConfigurerAdapter {
 
 		@Override
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java
index ee6dad15e1..4cea822c91 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java
@@ -91,11 +91,6 @@ public class NamespaceSessionManagementTests {
 		assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
 	}
 
-	@EnableWebSecurity
-	static class SessionManagementConfig extends WebSecurityConfigurerAdapter {
-
-	}
-
 	@Test
 	public void authenticateWhenUsingInvalidSessionUrlThenMatchesNamespace() throws Exception {
 		this.spring.register(CustomSessionManagementConfig.class).autowire();
@@ -157,6 +152,104 @@ public class NamespaceSessionManagementTests {
 		verify(sessionRegistry).registerNewSession(any(String.class), any(Object.class));
 	}
 
+	// gh-3371
+	@Test
+	public void authenticateWhenUsingCustomInvalidSessionStrategyThenMatchesNamespace() throws Exception {
+		this.spring.register(InvalidSessionStrategyConfig.class).autowire();
+
+		this.mvc.perform(get("/auth").with(request -> {
+			request.setRequestedSessionIdValid(false);
+			request.setRequestedSessionId("id");
+			return request;
+		})).andExpect(status().isOk());
+
+		verifyBean(InvalidSessionStrategy.class).onInvalidSessionDetected(any(HttpServletRequest.class),
+				any(HttpServletResponse.class));
+	}
+
+	@Test
+	public void authenticateWhenUsingCustomSessionAuthenticationStrategyThenMatchesNamespace() throws Exception {
+		this.spring.register(RefsSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
+				.autowire();
+
+		this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk());
+
+		verifyBean(SessionAuthenticationStrategy.class).onAuthentication(any(Authentication.class),
+				any(HttpServletRequest.class), any(HttpServletResponse.class));
+	}
+
+	@Test
+	public void authenticateWhenNoSessionFixationProtectionThenMatchesNamespace() throws Exception {
+		this.spring
+				.register(SFPNoneSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
+				.autowire();
+
+		MockHttpSession givenSession = new MockHttpSession();
+		String givenSessionId = givenSession.getId();
+		MockHttpSession resultingSession = (MockHttpSession) this.mvc
+				.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
+				.andExpect(status().isOk()).andReturn().getRequest().getSession(false);
+
+		assertThat(givenSessionId).isEqualTo(resultingSession.getId());
+	}
+
+	@Test
+	public void authenticateWhenMigrateSessionFixationProtectionThenMatchesNamespace() throws Exception {
+		this.spring.register(SFPMigrateSessionManagementConfig.class, BasicController.class,
+				UserDetailsServiceConfig.class).autowire();
+
+		MockHttpSession givenSession = new MockHttpSession();
+		String givenSessionId = givenSession.getId();
+		givenSession.setAttribute("name", "value");
+
+		MockHttpSession resultingSession = (MockHttpSession) this.mvc
+				.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
+				.andExpect(status().isOk()).andReturn().getRequest().getSession(false);
+
+		assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
+		assertThat(resultingSession.getAttribute("name")).isEqualTo("value");
+	}
+
+	// SEC-2913
+	@Test
+	public void authenticateWhenUsingSessionFixationProtectionThenUsesNonNullEventPublisher() throws Exception {
+		this.spring.register(SFPPostProcessedConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		this.mvc.perform(get("/auth").session(new MockHttpSession()).with(httpBasic("user", "password")))
+				.andExpect(status().isNotFound());
+
+		verifyBean(MockEventListener.class).onApplicationEvent(any(SessionFixationProtectionEvent.class));
+	}
+
+	@Test
+	public void authenticateWhenNewSessionFixationProtectionThenMatchesNamespace() throws Exception {
+		this.spring.register(SFPNewSessionSessionManagementConfig.class, UserDetailsServiceConfig.class).autowire();
+
+		MockHttpSession givenSession = new MockHttpSession();
+		String givenSessionId = givenSession.getId();
+		givenSession.setAttribute("name", "value");
+
+		MockHttpSession resultingSession = (MockHttpSession) this.mvc
+				.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
+				.andExpect(status().isNotFound()).andReturn().getRequest().getSession(false);
+
+		assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
+		assertThat(resultingSession.getAttribute("name")).isNull();
+	}
+
+	private  T verifyBean(Class clazz) {
+		return verify(this.spring.getContext().getBean(clazz));
+	}
+
+	private static SessionResultMatcher session() {
+		return new SessionResultMatcher();
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementConfig extends WebSecurityConfigurerAdapter {
+
+	}
+
 	@EnableWebSecurity
 	static class CustomSessionManagementConfig extends WebSecurityConfigurerAdapter {
 
@@ -188,21 +281,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	// gh-3371
-	@Test
-	public void authenticateWhenUsingCustomInvalidSessionStrategyThenMatchesNamespace() throws Exception {
-		this.spring.register(InvalidSessionStrategyConfig.class).autowire();
-
-		this.mvc.perform(get("/auth").with(request -> {
-			request.setRequestedSessionIdValid(false);
-			request.setRequestedSessionId("id");
-			return request;
-		})).andExpect(status().isOk());
-
-		verifyBean(InvalidSessionStrategy.class).onInvalidSessionDetected(any(HttpServletRequest.class),
-				any(HttpServletResponse.class));
-	}
-
 	@EnableWebSecurity
 	static class InvalidSessionStrategyConfig extends WebSecurityConfigurerAdapter {
 
@@ -224,17 +302,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	@Test
-	public void authenticateWhenUsingCustomSessionAuthenticationStrategyThenMatchesNamespace() throws Exception {
-		this.spring.register(RefsSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
-				.autowire();
-
-		this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk());
-
-		verifyBean(SessionAuthenticationStrategy.class).onAuthentication(any(Authentication.class),
-				any(HttpServletRequest.class), any(HttpServletResponse.class));
-	}
-
 	@EnableWebSecurity
 	static class RefsSessionManagementConfig extends WebSecurityConfigurerAdapter {
 
@@ -258,21 +325,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	@Test
-	public void authenticateWhenNoSessionFixationProtectionThenMatchesNamespace() throws Exception {
-		this.spring
-				.register(SFPNoneSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
-				.autowire();
-
-		MockHttpSession givenSession = new MockHttpSession();
-		String givenSessionId = givenSession.getId();
-		MockHttpSession resultingSession = (MockHttpSession) this.mvc
-				.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
-				.andExpect(status().isOk()).andReturn().getRequest().getSession(false);
-
-		assertThat(givenSessionId).isEqualTo(resultingSession.getId());
-	}
-
 	@EnableWebSecurity
 	static class SFPNoneSessionManagementConfig extends WebSecurityConfigurerAdapter {
 
@@ -289,23 +341,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	@Test
-	public void authenticateWhenMigrateSessionFixationProtectionThenMatchesNamespace() throws Exception {
-		this.spring.register(SFPMigrateSessionManagementConfig.class, BasicController.class,
-				UserDetailsServiceConfig.class).autowire();
-
-		MockHttpSession givenSession = new MockHttpSession();
-		String givenSessionId = givenSession.getId();
-		givenSession.setAttribute("name", "value");
-
-		MockHttpSession resultingSession = (MockHttpSession) this.mvc
-				.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
-				.andExpect(status().isOk()).andReturn().getRequest().getSession(false);
-
-		assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
-		assertThat(resultingSession.getAttribute("name")).isEqualTo("value");
-	}
-
 	@EnableWebSecurity
 	static class SFPMigrateSessionManagementConfig extends WebSecurityConfigurerAdapter {
 
@@ -321,17 +356,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	// SEC-2913
-	@Test
-	public void authenticateWhenUsingSessionFixationProtectionThenUsesNonNullEventPublisher() throws Exception {
-		this.spring.register(SFPPostProcessedConfig.class, UserDetailsServiceConfig.class).autowire();
-
-		this.mvc.perform(get("/auth").session(new MockHttpSession()).with(httpBasic("user", "password")))
-				.andExpect(status().isNotFound());
-
-		verifyBean(MockEventListener.class).onApplicationEvent(any(SessionFixationProtectionEvent.class));
-	}
-
 	@EnableWebSecurity
 	static class SFPPostProcessedConfig extends WebSecurityConfigurerAdapter {
 
@@ -352,22 +376,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	@Test
-	public void authenticateWhenNewSessionFixationProtectionThenMatchesNamespace() throws Exception {
-		this.spring.register(SFPNewSessionSessionManagementConfig.class, UserDetailsServiceConfig.class).autowire();
-
-		MockHttpSession givenSession = new MockHttpSession();
-		String givenSessionId = givenSession.getId();
-		givenSession.setAttribute("name", "value");
-
-		MockHttpSession resultingSession = (MockHttpSession) this.mvc
-				.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
-				.andExpect(status().isNotFound()).andReturn().getRequest().getSession(false);
-
-		assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
-		assertThat(resultingSession.getAttribute("name")).isNull();
-	}
-
 	@EnableWebSecurity
 	static class SFPNewSessionSessionManagementConfig extends WebSecurityConfigurerAdapter {
 
@@ -384,10 +392,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	private  T verifyBean(Class clazz) {
-		return verify(this.spring.getContext().getBean(clazz));
-	}
-
 	static class MockEventListener implements ApplicationListener {
 
 		List events = new ArrayList<>();
@@ -431,10 +435,6 @@ public class NamespaceSessionManagementTests {
 
 	}
 
-	private static SessionResultMatcher session() {
-		return new SessionResultMatcher();
-	}
-
 	private static class SessionResultMatcher implements ResultMatcher {
 
 		private String id;
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java
index 0af8e42362..8d8fd76f3a 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java
@@ -55,6 +55,13 @@ public class PermitAllSupportTests {
 		this.mvc.perform(get("/app/abc").with(csrf()).contextPath("/app")).andExpect(status().isFound());
 	}
 
+	@Test
+	public void configureWhenNotAuthorizeRequestsThenException() {
+		assertThatCode(() -> this.spring.register(NoAuthorizedUrlsConfig.class).autowire())
+				.isInstanceOf(BeanCreationException.class)
+				.hasMessageContaining("permitAll only works with HttpSecurity.authorizeRequests");
+	}
+
 	@EnableWebSecurity
 	static class PermitAllConfig extends WebSecurityConfigurerAdapter {
 
@@ -73,13 +80,6 @@ public class PermitAllSupportTests {
 
 	}
 
-	@Test
-	public void configureWhenNotAuthorizeRequestsThenException() {
-		assertThatCode(() -> this.spring.register(NoAuthorizedUrlsConfig.class).autowire())
-				.isInstanceOf(BeanCreationException.class)
-				.hasMessageContaining("permitAll only works with HttpSecurity.authorizeRequests");
-	}
-
 	@EnableWebSecurity
 	static class NoAuthorizedUrlsConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
index fadb69cbbe..8fd6a64f0b 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
@@ -50,6 +50,20 @@ public class PortMapperConfigurerTests {
 		this.mockMvc.perform(get("http://localhost:543")).andExpect(redirectedUrl("https://localhost:123"));
 	}
 
+	@Test
+	public void requestWhenPortMapperHttpMapsToInLambdaThenRedirectsToHttpsPort() throws Exception {
+		this.spring.register(HttpMapsToInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(get("http://localhost:543")).andExpect(redirectedUrl("https://localhost:123"));
+	}
+
+	@Test
+	public void requestWhenCustomPortMapperInLambdaThenRedirectsToHttpsPort() throws Exception {
+		this.spring.register(CustomPortMapperInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(get("http://localhost:543")).andExpect(redirectedUrl("https://localhost:123"));
+	}
+
 	@EnableWebSecurity
 	static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
 
@@ -69,13 +83,6 @@ public class PortMapperConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenPortMapperHttpMapsToInLambdaThenRedirectsToHttpsPort() throws Exception {
-		this.spring.register(HttpMapsToInLambdaConfig.class).autowire();
-
-		this.mockMvc.perform(get("http://localhost:543")).andExpect(redirectedUrl("https://localhost:123"));
-	}
-
 	@EnableWebSecurity
 	static class HttpMapsToInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -96,13 +103,6 @@ public class PortMapperConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenCustomPortMapperInLambdaThenRedirectsToHttpsPort() throws Exception {
-		this.spring.register(CustomPortMapperInLambdaConfig.class).autowire();
-
-		this.mockMvc.perform(get("http://localhost:543")).andExpect(redirectedUrl("https://localhost:123"));
-	}
-
 	@EnableWebSecurity
 	static class CustomPortMapperInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
index cb312190c3..9de0c521d8 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
@@ -86,35 +86,6 @@ public class RememberMeConfigurerTests {
 				.param("remember-me", "true").with(csrf()))).hasMessageContaining("UserDetailsService is required");
 	}
 
-	@EnableWebSecurity
-	static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
-				.formLogin()
-					.and()
-				.rememberMe();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) {
-			User user = (User) PasswordEncodedUser.user();
-			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
-			provider.setUserDetailsService(new InMemoryUserDetailsManager(Collections.singletonList(user)));
-			// @formatter:off
-			auth
-				.authenticationProvider(provider);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnRememberMeAuthenticationFilter() {
 		this.spring.register(ObjectPostProcessorConfig.class).autowire();
@@ -122,44 +93,6 @@ public class RememberMeConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(RememberMeAuthenticationFilter.class));
 	}
 
-	@EnableWebSecurity
-	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
-
-		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.rememberMe()
-					.userDetailsService(new AuthenticationManagerBuilder(objectPostProcessor).getDefaultUserDetailsService());
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@Bean
-		static ObjectPostProcessor objectPostProcessor() {
-			return objectPostProcessor;
-		}
-
-	}
-
-	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
-
-		@Override
-		public  O postProcess(O object) {
-			return object;
-		}
-
-	}
-
 	@Test
 	public void rememberMeWhenInvokedTwiceThenUsesOriginalUserDetailsService() throws Exception {
 		when(DuplicateDoesNotOverrideConfig.userDetailsService.loadUserByUsername(anyString()))
@@ -171,40 +104,6 @@ public class RememberMeConfigurerTests {
 		verify(DuplicateDoesNotOverrideConfig.userDetailsService).loadUserByUsername("user");
 	}
 
-	@EnableWebSecurity
-	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
-
-		static UserDetailsService userDetailsService = mock(UserDetailsService.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.rememberMe()
-					.userDetailsService(userDetailsService)
-					.and()
-				.rememberMe();
-			// @formatter:on
-		}
-
-		@Override
-		@Bean
-		public UserDetailsService userDetailsService() {
-			return new InMemoryUserDetailsManager(
-			// @formatter:off
-					User.withDefaultPasswordEncoder()
-							.username("user")
-							.password("password")
-							.roles("USER")
-							.build()
-					// @formatter:on
-			);
-		}
-
-	}
-
 	@Test
 	public void loginWhenRememberMeTrueThenRespondsWithRememberMeCookie() throws Exception {
 		this.spring.register(RememberMeConfig.class).autowire();
@@ -255,6 +154,152 @@ public class RememberMeConfigurerTests {
 				.andExpect(redirectedUrl("http://localhost/login"));
 	}
 
+	@Test
+	public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception {
+		this.spring.register(RememberMeInLambdaConfig.class).autowire();
+
+		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
+				.param("remember-me", "true")).andExpect(cookie().exists("remember-me"));
+	}
+
+	@Test
+	public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception {
+		this.spring.register(RememberMeCookieDomainConfig.class).autowire();
+
+		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
+				.param("remember-me", "true")).andExpect(cookie().exists("remember-me"))
+				.andExpect(cookie().domain("remember-me", "spring.io"));
+	}
+
+	@Test
+	public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception {
+		this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire();
+
+		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
+				.param("remember-me", "true")).andExpect(cookie().exists("remember-me"))
+				.andExpect(cookie().domain("remember-me", "spring.io"));
+	}
+
+	@Test
+	public void configureWhenRememberMeCookieNameAndRememberMeServicesThenException() {
+		assertThatThrownBy(() -> this.spring.register(RememberMeCookieNameAndRememberMeServicesConfig.class).autowire())
+				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class)
+				.hasMessageContaining("Can not set rememberMeCookieName and custom rememberMeServices.");
+	}
+
+	@Test
+	public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServicesIsUsed() throws Exception {
+		this.spring.register(FallbackRememberMeKeyConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
+				.param("password", "password").param("remember-me", "true")).andReturn();
+		Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
+
+		this.mvc.perform(get("/abc").cookie(rememberMeCookie)).andExpect(authenticated()
+				.withAuthentication(auth -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class)));
+	}
+
+	@EnableWebSecurity
+	static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().hasRole("USER")
+					.and()
+				.formLogin()
+					.and()
+				.rememberMe();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) {
+			User user = (User) PasswordEncodedUser.user();
+			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+			provider.setUserDetailsService(new InMemoryUserDetailsManager(Collections.singletonList(user)));
+			// @formatter:off
+			auth
+				.authenticationProvider(provider);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
+
+		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.rememberMe()
+					.userDetailsService(new AuthenticationManagerBuilder(objectPostProcessor).getDefaultUserDetailsService());
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@Bean
+		static ObjectPostProcessor objectPostProcessor() {
+			return objectPostProcessor;
+		}
+
+	}
+
+	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
+
+		@Override
+		public  O postProcess(O object) {
+			return object;
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
+
+		static UserDetailsService userDetailsService = mock(UserDetailsService.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.rememberMe()
+					.userDetailsService(userDetailsService)
+					.and()
+				.rememberMe();
+			// @formatter:on
+		}
+
+		@Override
+		@Bean
+		public UserDetailsService userDetailsService() {
+			return new InMemoryUserDetailsManager(
+			// @formatter:off
+					User.withDefaultPasswordEncoder()
+							.username("user")
+							.password("password")
+							.roles("USER")
+							.build()
+					// @formatter:on
+			);
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class RememberMeConfig extends WebSecurityConfigurerAdapter {
 
@@ -282,14 +327,6 @@ public class RememberMeConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception {
-		this.spring.register(RememberMeInLambdaConfig.class).autowire();
-
-		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
-				.param("remember-me", "true")).andExpect(cookie().exists("remember-me"));
-	}
-
 	@EnableWebSecurity
 	static class RememberMeInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -317,15 +354,6 @@ public class RememberMeConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception {
-		this.spring.register(RememberMeCookieDomainConfig.class).autowire();
-
-		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
-				.param("remember-me", "true")).andExpect(cookie().exists("remember-me"))
-				.andExpect(cookie().domain("remember-me", "spring.io"));
-	}
-
 	@EnableWebSecurity
 	static class RememberMeCookieDomainConfig extends WebSecurityConfigurerAdapter {
 
@@ -354,15 +382,6 @@ public class RememberMeConfigurerTests {
 
 	}
 
-	@Test
-	public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception {
-		this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire();
-
-		this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
-				.param("remember-me", "true")).andExpect(cookie().exists("remember-me"))
-				.andExpect(cookie().domain("remember-me", "spring.io"));
-	}
-
 	@EnableWebSecurity
 	static class RememberMeCookieDomainInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -393,13 +412,6 @@ public class RememberMeConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenRememberMeCookieNameAndRememberMeServicesThenException() {
-		assertThatThrownBy(() -> this.spring.register(RememberMeCookieNameAndRememberMeServicesConfig.class).autowire())
-				.isInstanceOf(BeanCreationException.class).hasRootCauseInstanceOf(IllegalArgumentException.class)
-				.hasMessageContaining("Can not set rememberMeCookieName and custom rememberMeServices.");
-	}
-
 	@EnableWebSecurity
 	static class RememberMeCookieNameAndRememberMeServicesConfig extends WebSecurityConfigurerAdapter {
 
@@ -432,18 +444,6 @@ public class RememberMeConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServicesIsUsed() throws Exception {
-		this.spring.register(FallbackRememberMeKeyConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
-				.param("password", "password").param("remember-me", "true")).andReturn();
-		Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
-
-		this.mvc.perform(get("/abc").cookie(rememberMeCookie)).andExpect(authenticated()
-				.withAuthentication(auth -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class)));
-	}
-
 	@EnableWebSecurity
 	static class FallbackRememberMeKeyConfig extends RememberMeConfig {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
index 9bb76f55b1..f1c2e15727 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
@@ -72,35 +72,6 @@ public class RequestCacheConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(RequestCacheAwareFilter.class));
 	}
 
-	@EnableWebSecurity
-	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
-
-		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.requestCache();
-			// @formatter:on
-		}
-
-		@Bean
-		static ObjectPostProcessor objectPostProcessor() {
-			return objectPostProcessor;
-		}
-
-	}
-
-	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
-
-		@Override
-		public  O postProcess(O object) {
-			return object;
-		}
-
-	}
-
 	@Test
 	public void getWhenInvokingExceptionHandlingTwiceThenOriginalEntryPointUsed() throws Exception {
 		this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
@@ -111,24 +82,6 @@ public class RequestCacheConfigurerTests {
 				any(HttpServletResponse.class));
 	}
 
-	@EnableWebSecurity
-	static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
-
-		static RequestCache requestCache = mock(RequestCache.class);
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.requestCache()
-					.requestCache(requestCache)
-					.and()
-				.requestCache();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void getWhenBookmarkedUrlIsFaviconIcoThenPostAuthenticationRedirectsToRoot() throws Exception {
 		this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
@@ -242,22 +195,6 @@ public class RequestCacheConfigurerTests {
 		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
 	}
 
-	@EnableWebSecurity
-	static class RequestCacheDefaultsConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.formLogin();
-			// @formatter:on
-		}
-
-	}
-
 	// gh-6102
 	@Test
 	public void getWhenRequestCacheIsDisabledThenExceptionTranslationFilterDoesNotStoreRequest() throws Exception {
@@ -282,6 +219,101 @@ public class RequestCacheConfigurerTests {
 		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
 	}
 
+	@Test
+	public void getWhenRequestCacheIsDisabledInLambdaThenExceptionTranslationFilterDoesNotStoreRequest()
+			throws Exception {
+		this.spring.register(RequestCacheDisabledInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
+
+		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
+
+		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
+	}
+
+	@Test
+	public void getWhenRequestCacheInLambdaThenRedirectedToCachedPage() throws Exception {
+		this.spring.register(RequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
+
+		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
+
+		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/bob"));
+	}
+
+	@Test
+	public void getWhenCustomRequestCacheInLambdaThenCustomRequestCacheUsed() throws Exception {
+		this.spring.register(CustomRequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
+
+		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
+
+		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
+	}
+
+	private static RequestBuilder formLogin(MockHttpSession session) {
+		return post("/login").param("username", "user").param("password", "password").session(session).with(csrf());
+	}
+
+	@EnableWebSecurity
+	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
+
+		static ObjectPostProcessor objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requestCache();
+			// @formatter:on
+		}
+
+		@Bean
+		static ObjectPostProcessor objectPostProcessor() {
+			return objectPostProcessor;
+		}
+
+	}
+
+	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
+
+		@Override
+		public  O postProcess(O object) {
+			return object;
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
+
+		static RequestCache requestCache = mock(RequestCache.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requestCache()
+					.requestCache(requestCache)
+					.and()
+				.requestCache();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class RequestCacheDefaultsConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.formLogin();
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class RequestCacheDisabledConfig extends WebSecurityConfigurerAdapter {
 
@@ -293,16 +325,6 @@ public class RequestCacheConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenRequestCacheIsDisabledInLambdaThenExceptionTranslationFilterDoesNotStoreRequest()
-			throws Exception {
-		this.spring.register(RequestCacheDisabledInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
-
-		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
-
-		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
-	}
-
 	@EnableWebSecurity
 	static class RequestCacheDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -321,15 +343,6 @@ public class RequestCacheConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenRequestCacheInLambdaThenRedirectedToCachedPage() throws Exception {
-		this.spring.register(RequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
-
-		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
-
-		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/bob"));
-	}
-
 	@EnableWebSecurity
 	static class RequestCacheInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -348,15 +361,6 @@ public class RequestCacheConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenCustomRequestCacheInLambdaThenCustomRequestCacheUsed() throws Exception {
-		this.spring.register(CustomRequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
-
-		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
-
-		this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
-	}
-
 	@EnableWebSecurity
 	static class CustomRequestCacheInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -395,8 +399,4 @@ public class RequestCacheConfigurerTests {
 
 	}
 
-	private static RequestBuilder formLogin(MockHttpSession session) {
-		return post("/login").param("username", "user").param("password", "password").session(session).with(csrf());
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
index ae744a06f5..9abd316d03 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
@@ -52,6 +52,14 @@ public class RequestMatcherConfigurerTests {
 		this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden());
 	}
 
+	@Test
+	public void authorizeRequestsWhenInvokedMultipleTimesInLambdaThenChainsPaths() throws Exception {
+		this.spring.register(AuthorizeRequestInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/oauth/abc")).andExpect(status().isForbidden());
+		this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden());
+	}
+
 	@EnableWebSecurity
 	static class Sec2908Config extends WebSecurityConfigurerAdapter {
 
@@ -72,14 +80,6 @@ public class RequestMatcherConfigurerTests {
 
 	}
 
-	@Test
-	public void authorizeRequestsWhenInvokedMultipleTimesInLambdaThenChainsPaths() throws Exception {
-		this.spring.register(AuthorizeRequestInLambdaConfig.class).autowire();
-
-		this.mvc.perform(get("/oauth/abc")).andExpect(status().isForbidden());
-		this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class AuthorizeRequestInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
index 2bfd5fda47..4d7b7e052d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
@@ -71,6 +71,51 @@ public class SecurityContextConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(SecurityContextPersistenceFilter.class));
 	}
 
+	@Test
+	public void securityContextWhenInvokedTwiceThenUsesOriginalSecurityContextRepository() throws Exception {
+		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
+		when(DuplicateDoesNotOverrideConfig.SCR.loadContext(any())).thenReturn(mock(SecurityContext.class));
+
+		this.mvc.perform(get("/"));
+
+		verify(DuplicateDoesNotOverrideConfig.SCR).loadContext(any(HttpRequestResponseHolder.class));
+	}
+
+	// SEC-2932
+	@Test
+	public void securityContextWhenSecurityContextRepositoryNotConfiguredThenDoesNotThrowException() throws Exception {
+		this.spring.register(SecurityContextRepositoryDefaultsSecurityContextRepositoryConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+	}
+
+	@Test
+	public void requestWhenSecurityContextWithDefaultsInLambdaThenSessionIsCreated() throws Exception {
+		this.spring.register(SecurityContextWithDefaultsInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNotNull();
+	}
+
+	@Test
+	public void requestWhenSecurityContextDisabledInLambdaThenContextNotSavedInSession() throws Exception {
+		this.spring.register(SecurityContextDisabledInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNull();
+	}
+
+	@Test
+	public void requestWhenNullSecurityContextRepositoryInLambdaThenContextNotSavedInSession() throws Exception {
+		this.spring.register(NullSecurityContextRepositoryInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNull();
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -100,16 +145,6 @@ public class SecurityContextConfigurerTests {
 
 	}
 
-	@Test
-	public void securityContextWhenInvokedTwiceThenUsesOriginalSecurityContextRepository() throws Exception {
-		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
-		when(DuplicateDoesNotOverrideConfig.SCR.loadContext(any())).thenReturn(mock(SecurityContext.class));
-
-		this.mvc.perform(get("/"));
-
-		verify(DuplicateDoesNotOverrideConfig.SCR).loadContext(any(HttpRequestResponseHolder.class));
-	}
-
 	@EnableWebSecurity
 	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
@@ -128,14 +163,6 @@ public class SecurityContextConfigurerTests {
 
 	}
 
-	// SEC-2932
-	@Test
-	public void securityContextWhenSecurityContextRepositoryNotConfiguredThenDoesNotThrowException() throws Exception {
-		this.spring.register(SecurityContextRepositoryDefaultsSecurityContextRepositoryConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class SecurityContextRepositoryDefaultsSecurityContextRepositoryConfig extends WebSecurityConfigurerAdapter {
@@ -171,15 +198,6 @@ public class SecurityContextConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenSecurityContextWithDefaultsInLambdaThenSessionIsCreated() throws Exception {
-		this.spring.register(SecurityContextWithDefaultsInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-		assertThat(session).isNotNull();
-	}
-
 	@EnableWebSecurity
 	static class SecurityContextWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -203,15 +221,6 @@ public class SecurityContextConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenSecurityContextDisabledInLambdaThenContextNotSavedInSession() throws Exception {
-		this.spring.register(SecurityContextDisabledInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-		assertThat(session).isNull();
-	}
-
 	@EnableWebSecurity
 	static class SecurityContextDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -235,15 +244,6 @@ public class SecurityContextConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenNullSecurityContextRepositoryInLambdaThenContextNotSavedInSession() throws Exception {
-		this.spring.register(NullSecurityContextRepositoryInLambdaConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
-		HttpSession session = mvcResult.getRequest().getSession(false);
-		assertThat(session).isNull();
-	}
-
 	@EnableWebSecurity
 	static class NullSecurityContextRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
index b94cbdf0eb..0850eb24ca 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
@@ -93,6 +93,127 @@ public class ServletApiConfigurerTests {
 				.postProcess(any(SecurityContextHolderAwareRequestFilter.class));
 	}
 
+	// SEC-2215
+	@Test
+	public void configureWhenUsingDefaultsThenAuthenticationManagerIsNotNull() {
+		this.spring.register(ServletApiConfig.class).autowire();
+
+		assertThat(this.spring.getContext().getBean("customAuthenticationManager")).isNotNull();
+	}
+
+	@Test
+	public void configureWhenUsingDefaultsThenAuthenticationEntryPointIsLogin() throws Exception {
+		this.spring.register(ServletApiConfig.class).autowire();
+
+		this.mvc.perform(formLogin()).andExpect(status().isFound());
+	}
+
+	// SEC-2926
+	@Test
+	public void configureWhenUsingDefaultsThenRolePrefixIsSet() throws Exception {
+		this.spring.register(ServletApiConfig.class, AdminController.class).autowire();
+
+		this.mvc.perform(
+				get("/admin").with(authentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN"))))
+				.andExpect(status().isOk());
+	}
+
+	@Test
+	public void requestWhenCustomAuthenticationEntryPointThenEntryPointUsed() throws Exception {
+		this.spring.register(CustomEntryPointConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(CustomEntryPointConfig.ENTRYPOINT).commence(any(HttpServletRequest.class),
+				any(HttpServletResponse.class), any(AuthenticationException.class));
+	}
+
+	@Test
+	public void servletApiWhenInvokedTwiceThenUsesOriginalRole() throws Exception {
+		this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class, AdminController.class).autowire();
+
+		this.mvc.perform(
+				get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
+				.andExpect(status().isOk());
+
+		this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
+				.andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void configureWhenSharedObjectTrustResolverThenTrustResolverUsed() throws Exception {
+		this.spring.register(SharedTrustResolverConfig.class).autowire();
+
+		this.mvc.perform(get("/"));
+
+		verify(SharedTrustResolverConfig.TR, atLeastOnce()).isAnonymous(any());
+	}
+
+	@Test
+	public void requestWhenServletApiWithDefaultsInLambdaThenUsesDefaultRolePrefix() throws Exception {
+		this.spring.register(ServletApiWithDefaultsInLambdaConfig.class, AdminController.class).autowire();
+
+		this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
+				.andExpect(status().isOk());
+	}
+
+	@Test
+	public void requestWhenRolePrefixInLambdaThenUsesCustomRolePrefix() throws Exception {
+		this.spring.register(RolePrefixInLambdaConfig.class, AdminController.class).autowire();
+
+		this.mvc.perform(
+				get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
+				.andExpect(status().isOk());
+
+		this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
+				.andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void checkSecurityContextAwareAndLogoutFilterHasSameSizeAndHasLogoutSuccessEventPublishingLogoutHandler() {
+		this.spring.register(ServletApiWithLogoutConfig.class);
+
+		SecurityContextHolderAwareRequestFilter scaFilter = getFilter(SecurityContextHolderAwareRequestFilter.class);
+		LogoutFilter logoutFilter = getFilter(LogoutFilter.class);
+
+		LogoutHandler lfLogoutHandler = getFieldValue(logoutFilter, "handler");
+		assertThat(lfLogoutHandler).isInstanceOf(CompositeLogoutHandler.class);
+
+		List scaLogoutHandlers = getFieldValue(scaFilter, "logoutHandlers");
+		List lfLogoutHandlers = getFieldValue(lfLogoutHandler, "logoutHandlers");
+
+		assertThat(scaLogoutHandlers).hasSameSizeAs(lfLogoutHandlers);
+
+		assertThat(scaLogoutHandlers).hasAtLeastOneElementOfType(LogoutSuccessEventPublishingLogoutHandler.class);
+		assertThat(lfLogoutHandlers).hasAtLeastOneElementOfType(LogoutSuccessEventPublishingLogoutHandler.class);
+	}
+
+	@Test
+	public void logoutServletApiWhenCsrfDisabled() throws Exception {
+		ConfigurableWebApplicationContext context = this.spring.register(CsrfDisabledConfig.class).getContext();
+		MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
+		MvcResult mvcResult = mockMvc.perform(get("/")).andReturn();
+		assertThat(mvcResult.getRequest().getSession(false)).isNull();
+	}
+
+	private  T getFilter(Class filterClass) {
+		return (T) getFilters().stream().filter(filterClass::isInstance).findFirst().orElse(null);
+	}
+
+	private List getFilters() {
+		FilterChainProxy proxy = this.spring.getContext().getBean(FilterChainProxy.class);
+		return proxy.getFilters("/");
+	}
+
+	private  T getFieldValue(Object target, String fieldName) {
+		try {
+			return (T) FieldUtils.getFieldValue(target, fieldName);
+		}
+		catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -122,31 +243,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	// SEC-2215
-	@Test
-	public void configureWhenUsingDefaultsThenAuthenticationManagerIsNotNull() {
-		this.spring.register(ServletApiConfig.class).autowire();
-
-		assertThat(this.spring.getContext().getBean("customAuthenticationManager")).isNotNull();
-	}
-
-	@Test
-	public void configureWhenUsingDefaultsThenAuthenticationEntryPointIsLogin() throws Exception {
-		this.spring.register(ServletApiConfig.class).autowire();
-
-		this.mvc.perform(formLogin()).andExpect(status().isFound());
-	}
-
-	// SEC-2926
-	@Test
-	public void configureWhenUsingDefaultsThenRolePrefixIsSet() throws Exception {
-		this.spring.register(ServletApiConfig.class, AdminController.class).autowire();
-
-		this.mvc.perform(
-				get("/admin").with(authentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN"))))
-				.andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class ServletApiConfig extends WebSecurityConfigurerAdapter {
 
@@ -166,16 +262,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenCustomAuthenticationEntryPointThenEntryPointUsed() throws Exception {
-		this.spring.register(CustomEntryPointConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(CustomEntryPointConfig.ENTRYPOINT).commence(any(HttpServletRequest.class),
-				any(HttpServletResponse.class), any(AuthenticationException.class));
-	}
-
 	@EnableWebSecurity
 	static class CustomEntryPointConfig extends WebSecurityConfigurerAdapter {
 
@@ -206,18 +292,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void servletApiWhenInvokedTwiceThenUsesOriginalRole() throws Exception {
-		this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class, AdminController.class).autowire();
-
-		this.mvc.perform(
-				get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
-				.andExpect(status().isOk());
-
-		this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
-				.andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
@@ -234,15 +308,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void configureWhenSharedObjectTrustResolverThenTrustResolverUsed() throws Exception {
-		this.spring.register(SharedTrustResolverConfig.class).autowire();
-
-		this.mvc.perform(get("/"));
-
-		verify(SharedTrustResolverConfig.TR, atLeastOnce()).isAnonymous(any());
-	}
-
 	@EnableWebSecurity
 	static class SharedTrustResolverConfig extends WebSecurityConfigurerAdapter {
 
@@ -258,14 +323,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenServletApiWithDefaultsInLambdaThenUsesDefaultRolePrefix() throws Exception {
-		this.spring.register(ServletApiWithDefaultsInLambdaConfig.class, AdminController.class).autowire();
-
-		this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
-				.andExpect(status().isOk());
-	}
-
 	@EnableWebSecurity
 	static class ServletApiWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -279,18 +336,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenRolePrefixInLambdaThenUsesCustomRolePrefix() throws Exception {
-		this.spring.register(RolePrefixInLambdaConfig.class, AdminController.class).autowire();
-
-		this.mvc.perform(
-				get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
-				.andExpect(status().isOk());
-
-		this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
-				.andExpect(status().isForbidden());
-	}
-
 	@EnableWebSecurity
 	static class RolePrefixInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -319,25 +364,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void checkSecurityContextAwareAndLogoutFilterHasSameSizeAndHasLogoutSuccessEventPublishingLogoutHandler() {
-		this.spring.register(ServletApiWithLogoutConfig.class);
-
-		SecurityContextHolderAwareRequestFilter scaFilter = getFilter(SecurityContextHolderAwareRequestFilter.class);
-		LogoutFilter logoutFilter = getFilter(LogoutFilter.class);
-
-		LogoutHandler lfLogoutHandler = getFieldValue(logoutFilter, "handler");
-		assertThat(lfLogoutHandler).isInstanceOf(CompositeLogoutHandler.class);
-
-		List scaLogoutHandlers = getFieldValue(scaFilter, "logoutHandlers");
-		List lfLogoutHandlers = getFieldValue(lfLogoutHandler, "logoutHandlers");
-
-		assertThat(scaLogoutHandlers).hasSameSizeAs(lfLogoutHandlers);
-
-		assertThat(scaLogoutHandlers).hasAtLeastOneElementOfType(LogoutSuccessEventPublishingLogoutHandler.class);
-		assertThat(lfLogoutHandlers).hasAtLeastOneElementOfType(LogoutSuccessEventPublishingLogoutHandler.class);
-	}
-
 	@EnableWebSecurity
 	static class ServletApiWithLogoutConfig extends WebSecurityConfigurerAdapter {
 
@@ -352,14 +378,6 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	@Test
-	public void logoutServletApiWhenCsrfDisabled() throws Exception {
-		ConfigurableWebApplicationContext context = this.spring.register(CsrfDisabledConfig.class).getContext();
-		MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
-		MvcResult mvcResult = mockMvc.perform(get("/")).andReturn();
-		assertThat(mvcResult.getRequest().getSession(false)).isNull();
-	}
-
 	@Configuration
 	@EnableWebSecurity
 	static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
@@ -386,22 +404,4 @@ public class ServletApiConfigurerTests {
 
 	}
 
-	private  T getFilter(Class filterClass) {
-		return (T) getFilters().stream().filter(filterClass::isInstance).findFirst().orElse(null);
-	}
-
-	private List getFilters() {
-		FilterChainProxy proxy = this.spring.getContext().getBean(FilterChainProxy.class);
-		return proxy.getFilters("/");
-	}
-
-	private  T getFieldValue(Object target, String fieldName) {
-		try {
-			return (T) FieldUtils.getFieldValue(target, fieldName);
-		}
-		catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java
index a200d42087..d2e84b594b 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java
@@ -103,6 +103,24 @@ public class SessionManagementConfigurerServlet31Tests {
 		assertThat(request.getSession().getAttribute("attribute1")).isEqualTo("value1");
 	}
 
+	private void loadConfig(Class... classes) {
+		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+		context.register(classes);
+		context.refresh();
+		this.context = context;
+		this.springSecurityFilterChain = this.context.getBean("springSecurityFilterChain", Filter.class);
+	}
+
+	private void login(Authentication auth) {
+		HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
+		HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(this.request, this.response);
+		repo.loadContext(requestResponseHolder);
+
+		SecurityContextImpl securityContextImpl = new SecurityContextImpl();
+		securityContextImpl.setAuthentication(auth);
+		repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
+	}
+
 	@EnableWebSecurity
 	static class SessionManagementDefaultSessionFixationServlet31Config extends WebSecurityConfigurerAdapter {
 
@@ -127,22 +145,4 @@ public class SessionManagementConfigurerServlet31Tests {
 
 	}
 
-	private void loadConfig(Class... classes) {
-		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-		context.register(classes);
-		context.refresh();
-		this.context = context;
-		this.springSecurityFilterChain = this.context.getBean("springSecurityFilterChain", Filter.class);
-	}
-
-	private void login(Authentication auth) {
-		HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
-		HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(this.request, this.response);
-		repo.loadContext(requestResponseHolder);
-
-		SecurityContextImpl securityContextImpl = new SecurityContextImpl();
-		securityContextImpl.setAuthentication(auth);
-		repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java
index 6cf6576b1b..ff7d81bae3 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java
@@ -55,6 +55,26 @@ public class SessionManagementConfigurerSessionCreationPolicyTests {
 		assertThat(result.getRequest().getSession(false)).isNull();
 	}
 
+	@Test
+	public void getWhenUserSessionCreationPolicyConfigurationThenOverrides() throws Exception {
+
+		this.spring.register(StatelessCreateSessionUserConfig.class).autowire();
+
+		MvcResult result = this.mvc.perform(get("/")).andReturn();
+
+		assertThat(result.getRequest().getSession(false)).isNull();
+	}
+
+	@Test
+	public void getWhenDefaultsThenLoginChallengeCreatesSession() throws Exception {
+
+		this.spring.register(DefaultConfig.class, BasicController.class).autowire();
+
+		MvcResult result = this.mvc.perform(get("/")).andExpect(status().isUnauthorized()).andReturn();
+
+		assertThat(result.getRequest().getSession(false)).isNotNull();
+	}
+
 	@EnableWebSecurity
 	static class StatelessCreateSessionSharedObjectConfig extends WebSecurityConfigurerAdapter {
 
@@ -66,16 +86,6 @@ public class SessionManagementConfigurerSessionCreationPolicyTests {
 
 	}
 
-	@Test
-	public void getWhenUserSessionCreationPolicyConfigurationThenOverrides() throws Exception {
-
-		this.spring.register(StatelessCreateSessionUserConfig.class).autowire();
-
-		MvcResult result = this.mvc.perform(get("/")).andReturn();
-
-		assertThat(result.getRequest().getSession(false)).isNull();
-	}
-
 	@EnableWebSecurity
 	static class StatelessCreateSessionUserConfig extends WebSecurityConfigurerAdapter {
 
@@ -92,16 +102,6 @@ public class SessionManagementConfigurerSessionCreationPolicyTests {
 
 	}
 
-	@Test
-	public void getWhenDefaultsThenLoginChallengeCreatesSession() throws Exception {
-
-		this.spring.register(DefaultConfig.class, BasicController.class).autowire();
-
-		MvcResult result = this.mvc.perform(get("/")).andExpect(status().isUnauthorized()).andReturn();
-
-		assertThat(result.getRequest().getSession(false)).isNotNull();
-	}
-
 	@EnableWebSecurity
 	static class DefaultConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
index 8ce913f6b3..267135d6cf 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
@@ -90,25 +90,6 @@ public class SessionManagementConfigurerTests {
 				any(HttpServletResponse.class));
 	}
 
-	@EnableWebSecurity
-	static class SessionManagementRequestCacheConfig extends WebSecurityConfigurerAdapter {
-
-		static RequestCache REQUEST_CACHE;
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.requestCache()
-					.requestCache(REQUEST_CACHE)
-					.and()
-				.sessionManagement()
-					.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void sessionManagementWhenConfiguredThenDoesNotOverrideSecurityContextRepository() throws Exception {
 		SessionManagementSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO = mock(SecurityContextRepository.class);
@@ -122,25 +103,6 @@ public class SessionManagementConfigurerTests {
 				.saveContext(any(SecurityContext.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
 	}
 
-	@EnableWebSecurity
-	static class SessionManagementSecurityContextRepositoryConfig extends WebSecurityConfigurerAdapter {
-
-		static SecurityContextRepository SECURITY_CONTEXT_REPO;
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.securityContext()
-					.securityContextRepository(SECURITY_CONTEXT_REPO)
-					.and()
-				.sessionManagement()
-					.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void sessionManagementWhenInvokedTwiceThenUsesOriginalSessionCreationPolicy() throws Exception {
 		this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
@@ -151,22 +113,6 @@ public class SessionManagementConfigurerTests {
 		assertThat(session).isNull();
 	}
 
-	@EnableWebSecurity
-	static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.sessionManagement()
-					.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-					.and()
-				.sessionManagement();
-			// @formatter:on
-		}
-
-	}
-
 	// SEC-2137
 	@Test
 	public void getWhenSessionFixationDisabledAndConcurrencyControlEnabledThenSessionIsNotInvalidated()
@@ -181,32 +127,6 @@ public class SessionManagementConfigurerTests {
 		assertThat(mvcResult.getRequest().getSession().getId()).isEqualTo(sessionId);
 	}
 
-	@EnableWebSecurity
-	static class DisableSessionFixationEnableConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		public void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic()
-					.and()
-				.sessionManagement()
-					.sessionFixation().none()
-					.maximumSessions(1);
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void authenticateWhenNewSessionFixationProtectionInLambdaThenCreatesNewSession() throws Exception {
 		this.spring.register(SFPNewSessionInLambdaConfig.class).autowire();
@@ -223,34 +143,6 @@ public class SessionManagementConfigurerTests {
 		assertThat(resultingSession.getAttribute("name")).isNull();
 	}
 
-	@EnableWebSecurity
-	static class SFPNewSessionInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.sessionManagement(sessionManagement ->
-					sessionManagement
-						.sessionFixation(sessionFixation ->
-							sessionFixation.newSession()
-						)
-				)
-				.httpBasic(withDefaults());
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginWhenUserLoggedInAndMaxSessionsIsOneThenLoginPrevented() throws Exception {
 		this.spring.register(ConcurrencyControlConfig.class).autowire();
@@ -275,32 +167,6 @@ public class SessionManagementConfigurerTests {
 				.andExpect(status().isFound()).andExpect(redirectedUrl("/"));
 	}
 
-	@EnableWebSecurity
-	static class ConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		public void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.formLogin()
-					.and()
-				.sessionManagement()
-					.maximumSessions(1)
-					.maxSessionsPreventsLogin(true);
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void loginWhenUserLoggedInAndMaxSessionsOneInLambdaThenLoginPrevented() throws Exception {
 		this.spring.register(ConcurrencyControlInLambdaConfig.class).autowire();
@@ -311,36 +177,6 @@ public class SessionManagementConfigurerTests {
 				.andExpect(status().isFound()).andExpect(redirectedUrl("/login?error"));
 	}
 
-	@EnableWebSecurity
-	static class ConcurrencyControlInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		public void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.formLogin(withDefaults())
-				.sessionManagement(sessionManagement ->
-					sessionManagement
-						.sessionConcurrency(sessionConcurrency ->
-							sessionConcurrency
-								.maximumSessions(1)
-								.maxSessionsPreventsLogin(true)
-						)
-				);
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication()
-					.withUser(PasswordEncodedUser.user());
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenSessionCreationPolicyStateLessInLambdaThenNoSessionCreated() throws Exception {
 		this.spring.register(SessionCreationPolicyStateLessInLambdaConfig.class).autowire();
@@ -351,22 +187,6 @@ public class SessionManagementConfigurerTests {
 		assertThat(session).isNull();
 	}
 
-	@EnableWebSecurity
-	static class SessionCreationPolicyStateLessInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.sessionManagement(sessionManagement ->
-					sessionManagement
-						.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenRegisteringObjectPostProcessorThenInvokedOnSessionManagementFilter() {
 		ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@@ -419,6 +239,222 @@ public class SessionManagementConfigurerTests {
 				.postProcess(any(ChangeSessionIdAuthenticationStrategy.class));
 	}
 
+	@Test
+	public void getWhenAnonymousRequestAndTrustResolverSharedObjectReturnsAnonymousFalseThenSessionIsSaved()
+			throws Exception {
+		SharedTrustResolverConfig.TR = mock(AuthenticationTrustResolver.class);
+		when(SharedTrustResolverConfig.TR.isAnonymous(any())).thenReturn(false);
+		this.spring.register(SharedTrustResolverConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/")).andReturn();
+
+		assertThat(mvcResult.getRequest().getSession(false)).isNotNull();
+	}
+
+	@Test
+	public void whenOneSessionRegistryBeanThenUseIt() throws Exception {
+		SessionRegistryOneBeanConfig.SESSION_REGISTRY = mock(SessionRegistry.class);
+		this.spring.register(SessionRegistryOneBeanConfig.class).autowire();
+
+		MockHttpSession session = new MockHttpSession(this.spring.getContext().getServletContext());
+		this.mvc.perform(get("/").session(session));
+
+		verify(SessionRegistryOneBeanConfig.SESSION_REGISTRY).getSessionInformation(session.getId());
+	}
+
+	@Test
+	public void whenTwoSessionRegistryBeansThenUseNeither() throws Exception {
+		SessionRegistryTwoBeansConfig.SESSION_REGISTRY_ONE = mock(SessionRegistry.class);
+		SessionRegistryTwoBeansConfig.SESSION_REGISTRY_TWO = mock(SessionRegistry.class);
+		this.spring.register(SessionRegistryTwoBeansConfig.class).autowire();
+
+		MockHttpSession session = new MockHttpSession(this.spring.getContext().getServletContext());
+		this.mvc.perform(get("/").session(session));
+
+		verifyNoInteractions(SessionRegistryTwoBeansConfig.SESSION_REGISTRY_ONE);
+		verifyNoInteractions(SessionRegistryTwoBeansConfig.SESSION_REGISTRY_TWO);
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementRequestCacheConfig extends WebSecurityConfigurerAdapter {
+
+		static RequestCache REQUEST_CACHE;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requestCache()
+					.requestCache(REQUEST_CACHE)
+					.and()
+				.sessionManagement()
+					.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class SessionManagementSecurityContextRepositoryConfig extends WebSecurityConfigurerAdapter {
+
+		static SecurityContextRepository SECURITY_CONTEXT_REPO;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.securityContext()
+					.securityContextRepository(SECURITY_CONTEXT_REPO)
+					.and()
+				.sessionManagement()
+					.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.sessionManagement()
+					.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+					.and()
+				.sessionManagement();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class DisableSessionFixationEnableConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		public void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic()
+					.and()
+				.sessionManagement()
+					.sessionFixation().none()
+					.maximumSessions(1);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class SFPNewSessionInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.sessionManagement(sessionManagement ->
+					sessionManagement
+						.sessionFixation(sessionFixation ->
+							sessionFixation.newSession()
+						)
+				)
+				.httpBasic(withDefaults());
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ConcurrencyControlConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		public void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin()
+					.and()
+				.sessionManagement()
+					.maximumSessions(1)
+					.maxSessionsPreventsLogin(true);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class ConcurrencyControlInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		public void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.sessionManagement(sessionManagement ->
+					sessionManagement
+						.sessionConcurrency(sessionConcurrency ->
+							sessionConcurrency
+								.maximumSessions(1)
+								.maxSessionsPreventsLogin(true)
+						)
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class SessionCreationPolicyStateLessInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.sessionManagement(sessionManagement ->
+					sessionManagement
+						.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+				);
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -449,18 +485,6 @@ public class SessionManagementConfigurerTests {
 
 	}
 
-	@Test
-	public void getWhenAnonymousRequestAndTrustResolverSharedObjectReturnsAnonymousFalseThenSessionIsSaved()
-			throws Exception {
-		SharedTrustResolverConfig.TR = mock(AuthenticationTrustResolver.class);
-		when(SharedTrustResolverConfig.TR.isAnonymous(any())).thenReturn(false);
-		this.spring.register(SharedTrustResolverConfig.class).autowire();
-
-		MvcResult mvcResult = this.mvc.perform(get("/")).andReturn();
-
-		assertThat(mvcResult.getRequest().getSession(false)).isNotNull();
-	}
-
 	@EnableWebSecurity
 	static class SharedTrustResolverConfig extends WebSecurityConfigurerAdapter {
 
@@ -476,30 +500,6 @@ public class SessionManagementConfigurerTests {
 
 	}
 
-	@Test
-	public void whenOneSessionRegistryBeanThenUseIt() throws Exception {
-		SessionRegistryOneBeanConfig.SESSION_REGISTRY = mock(SessionRegistry.class);
-		this.spring.register(SessionRegistryOneBeanConfig.class).autowire();
-
-		MockHttpSession session = new MockHttpSession(this.spring.getContext().getServletContext());
-		this.mvc.perform(get("/").session(session));
-
-		verify(SessionRegistryOneBeanConfig.SESSION_REGISTRY).getSessionInformation(session.getId());
-	}
-
-	@Test
-	public void whenTwoSessionRegistryBeansThenUseNeither() throws Exception {
-		SessionRegistryTwoBeansConfig.SESSION_REGISTRY_ONE = mock(SessionRegistry.class);
-		SessionRegistryTwoBeansConfig.SESSION_REGISTRY_TWO = mock(SessionRegistry.class);
-		this.spring.register(SessionRegistryTwoBeansConfig.class).autowire();
-
-		MockHttpSession session = new MockHttpSession(this.spring.getContext().getServletContext());
-		this.mvc.perform(get("/").session(session));
-
-		verifyNoInteractions(SessionRegistryTwoBeansConfig.SESSION_REGISTRY_ONE);
-		verifyNoInteractions(SessionRegistryTwoBeansConfig.SESSION_REGISTRY_TWO);
-	}
-
 	@EnableWebSecurity
 	static class SessionRegistryOneBeanConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java
index e0ba32d1aa..1604b8e616 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java
@@ -98,41 +98,6 @@ public class UrlAuthorizationConfigurerTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
 	}
 
-	@EnableWebSecurity
-	@Configuration
-	@EnableWebMvc
-	static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.httpBasic().and()
-				.apply(new UrlAuthorizationConfigurer(getApplicationContext())).getRegistry()
-					.mvcMatchers("/path").hasRole("ADMIN");
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@RestController
-		static class PathController {
-
-			@RequestMapping("/path")
-			public String path() {
-				return "path";
-			}
-
-		}
-
-	}
-
 	@Test
 	public void mvcMatcherServletPath() throws Exception {
 		loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
@@ -176,6 +141,55 @@ public class UrlAuthorizationConfigurerTests {
 		assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
 	}
 
+	@Test
+	public void anonymousUrlAuthorization() {
+		loadConfig(AnonymousUrlAuthorizationConfig.class);
+	}
+
+	public void loadConfig(Class... configs) {
+		this.context = new AnnotationConfigWebApplicationContext();
+		this.context.register(configs);
+		this.context.setServletContext(new MockServletContext());
+		this.context.refresh();
+
+		this.context.getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
+	@EnableWebSecurity
+	@Configuration
+	@EnableWebMvc
+	static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic().and()
+				.apply(new UrlAuthorizationConfigurer(getApplicationContext())).getRegistry()
+					.mvcMatchers("/path").hasRole("ADMIN");
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@RestController
+		static class PathController {
+
+			@RequestMapping("/path")
+			public String path() {
+				return "path";
+			}
+
+		}
+
+	}
+
 	@EnableWebSecurity
 	@Configuration
 	@EnableWebMvc
@@ -211,11 +225,6 @@ public class UrlAuthorizationConfigurerTests {
 
 	}
 
-	@Test
-	public void anonymousUrlAuthorization() {
-		loadConfig(AnonymousUrlAuthorizationConfig.class);
-	}
-
 	@EnableWebSecurity
 	@Configuration
 	static class AnonymousUrlAuthorizationConfig extends WebSecurityConfigurerAdapter {
@@ -241,13 +250,4 @@ public class UrlAuthorizationConfigurerTests {
 
 	}
 
-	public void loadConfig(Class... configs) {
-		this.context = new AnnotationConfigWebApplicationContext();
-		this.context.register(configs);
-		this.context.setServletContext(new MockServletContext());
-		this.context.refresh();
-
-		this.context.getAutowireCapableBeanFactory().autowireBean(this);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java
index f0b8d56e78..8497fee4fd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java
@@ -103,25 +103,6 @@ public class UrlAuthorizationsTests {
 		this.mvc.perform(get("/role-admin")).andExpect(status().isForbidden());
 	}
 
-	@EnableWebSecurity
-	static class RoleConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.antMatchers("/role-user-authority").hasAnyAuthority("ROLE_USER")
-					.antMatchers("/role-admin-authority").hasAnyAuthority("ROLE_ADMIN")
-					.antMatchers("/role-user-admin-authority").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")
-					.antMatchers("/role-user").hasAnyRole("USER")
-					.antMatchers("/role-admin").hasAnyRole("ADMIN")
-					.antMatchers("/role-user-admin").hasAnyRole("USER", "ADMIN");
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void configureWhenNoAccessDecisionManagerThenDefaultsToAffirmativeBased() {
 		this.spring.register(NoSpecificAccessDecisionManagerConfig.class).autowire();
@@ -142,6 +123,25 @@ public class UrlAuthorizationsTests {
 		return null;
 	}
 
+	@EnableWebSecurity
+	static class RoleConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.antMatchers("/role-user-authority").hasAnyAuthority("ROLE_USER")
+					.antMatchers("/role-admin-authority").hasAnyAuthority("ROLE_ADMIN")
+					.antMatchers("/role-user-admin-authority").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")
+					.antMatchers("/role-user").hasAnyRole("USER")
+					.antMatchers("/role-admin").hasAnyRole("ADMIN")
+					.antMatchers("/role-user-admin").hasAnyRole("USER", "ADMIN");
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class NoSpecificAccessDecisionManagerConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
index 20d4245cd8..e497365b44 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
@@ -65,6 +65,40 @@ public class X509ConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(X509AuthenticationFilter.class));
 	}
 
+	@Test
+	public void x509WhenInvokedTwiceThenUsesOriginalSubjectPrincipalRegex() throws Exception {
+		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
+		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+
+		this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
+	}
+
+	@Test
+	public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception {
+		this.spring.register(DefaultsInLambdaConfig.class).autowire();
+		X509Certificate certificate = loadCert("rod.cer");
+
+		this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
+	}
+
+	@Test
+	public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
+		this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
+		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+
+		this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
+	}
+
+	private  T loadCert(String location) {
+		try (InputStream is = new ClassPathResource(location).getInputStream()) {
+			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+			return (T) certFactory.generateCertificate(is);
+		}
+		catch (Exception e) {
+			throw new IllegalArgumentException(e);
+		}
+	}
+
 	@EnableWebSecurity
 	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
 
@@ -94,14 +128,6 @@ public class X509ConfigurerTests {
 
 	}
 
-	@Test
-	public void x509WhenInvokedTwiceThenUsesOriginalSubjectPrincipalRegex() throws Exception {
-		this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
-		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
-
-		this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
-	}
-
 	@EnableWebSecurity
 	static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
 
@@ -127,14 +153,6 @@ public class X509ConfigurerTests {
 
 	}
 
-	@Test
-	public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception {
-		this.spring.register(DefaultsInLambdaConfig.class).autowire();
-		X509Certificate certificate = loadCert("rod.cer");
-
-		this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
-	}
-
 	@EnableWebSecurity
 	static class DefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -157,14 +175,6 @@ public class X509ConfigurerTests {
 
 	}
 
-	@Test
-	public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
-		this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
-		X509Certificate certificate = loadCert("rodatexampledotcom.cer");
-
-		this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
-	}
-
 	@EnableWebSecurity
 	static class SubjectPrincipalRegexInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -190,14 +200,4 @@ public class X509ConfigurerTests {
 
 	}
 
-	private  T loadCert(String location) {
-		try (InputStream is = new ClassPathResource(location).getInputStream()) {
-			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-			return (T) certFactory.generateCertificate(is);
-		}
-		catch (Exception e) {
-			throw new IllegalArgumentException(e);
-		}
-	}
-
 }
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 130fa378bb..edcc2600a5 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
@@ -584,6 +584,37 @@ public class OAuth2LoginConfigurerTests {
 				.scope(scopes).build();
 	}
 
+	private static OAuth2AccessTokenResponseClient createOauth2AccessTokenResponseClient() {
+		return request -> {
+			Map additionalParameters = new HashMap<>();
+			if (request.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) {
+				additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123");
+			}
+			return OAuth2AccessTokenResponse.withToken("accessToken123").tokenType(OAuth2AccessToken.TokenType.BEARER)
+					.additionalParameters(additionalParameters).build();
+		};
+	}
+
+	private static OAuth2UserService createOauth2UserService() {
+		Map userAttributes = Collections.singletonMap("name", "spring");
+		return request -> new DefaultOAuth2User(Collections.singleton(new OAuth2UserAuthority(userAttributes)),
+				userAttributes, "name");
+	}
+
+	private static OAuth2UserService createOidcUserService() {
+		OidcIdToken idToken = idToken().build();
+		return request -> new DefaultOidcUser(Collections.singleton(new OidcUserAuthority(idToken)), idToken);
+	}
+
+	private static GrantedAuthoritiesMapper createGrantedAuthoritiesMapper() {
+		return authorities -> {
+			boolean isOidc = OidcUserAuthority.class.isInstance(authorities.iterator().next());
+			List mappedAuthorities = new ArrayList<>(authorities);
+			mappedAuthorities.add(new SimpleGrantedAuthority(isOidc ? "ROLE_OIDC_USER" : "ROLE_OAUTH2_USER"));
+			return mappedAuthorities;
+		};
+	}
+
 	@EnableWebSecurity
 	static class OAuth2LoginConfig extends CommonWebSecurityConfigurerAdapter
 			implements ApplicationListener {
@@ -985,35 +1016,4 @@ public class OAuth2LoginConfigurerTests {
 
 	}
 
-	private static OAuth2AccessTokenResponseClient createOauth2AccessTokenResponseClient() {
-		return request -> {
-			Map additionalParameters = new HashMap<>();
-			if (request.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) {
-				additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123");
-			}
-			return OAuth2AccessTokenResponse.withToken("accessToken123").tokenType(OAuth2AccessToken.TokenType.BEARER)
-					.additionalParameters(additionalParameters).build();
-		};
-	}
-
-	private static OAuth2UserService createOauth2UserService() {
-		Map userAttributes = Collections.singletonMap("name", "spring");
-		return request -> new DefaultOAuth2User(Collections.singleton(new OAuth2UserAuthority(userAttributes)),
-				userAttributes, "name");
-	}
-
-	private static OAuth2UserService createOidcUserService() {
-		OidcIdToken idToken = idToken().build();
-		return request -> new DefaultOidcUser(Collections.singleton(new OidcUserAuthority(idToken)), idToken);
-	}
-
-	private static GrantedAuthoritiesMapper createGrantedAuthoritiesMapper() {
-		return authorities -> {
-			boolean isOidc = OidcUserAuthority.class.isInstance(authorities.iterator().next());
-			List mappedAuthorities = new ArrayList<>(authorities);
-			mappedAuthorities.add(new SimpleGrantedAuthority(isOidc ? "ROLE_OIDC_USER" : "ROLE_OAUTH2_USER"));
-			return mappedAuthorities;
-		};
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
index 4338f5a43c..04c077fd60 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
@@ -1327,7 +1327,89 @@ public class OAuth2ResourceServerConfigurerTests {
 				.isInstanceOf(NoUniqueBeanDefinitionException.class);
 	}
 
-	// -- support
+	private static  void registerMockBean(GenericApplicationContext context, String name, Class clazz) {
+		context.registerBean(name, clazz, () -> mock(clazz));
+	}
+
+	private static BearerTokenRequestPostProcessor bearerToken(String token) {
+		return new BearerTokenRequestPostProcessor(token);
+	}
+
+	private static ResultMatcher invalidRequestHeader(String message) {
+		return header().string(HttpHeaders.WWW_AUTHENTICATE,
+				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_request\", " + "error_description=\""),
+						new StringContains(message),
+						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
+	}
+
+	private static ResultMatcher invalidTokenHeader(String message) {
+		return header().string(HttpHeaders.WWW_AUTHENTICATE,
+				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_token\", " + "error_description=\""),
+						new StringContains(message),
+						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
+	}
+
+	private static ResultMatcher insufficientScopeHeader() {
+		return header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer " + "error=\"insufficient_scope\""
+				+ ", error_description=\"The request requires higher privileges than provided by the access token.\""
+				+ ", error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
+	}
+
+	private String jwkSet() {
+		return new JWKSet(new RSAKey.Builder(TestKeys.DEFAULT_PUBLIC_KEY).keyID("1").build()).toString();
+	}
+
+	private String jwtFromIssuer(String issuer) throws Exception {
+		Map claims = new HashMap<>();
+		claims.put(ISS, issuer);
+		claims.put(SUB, "test-subject");
+		claims.put("scope", "message:read");
+		JWSObject jws = new JWSObject(new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("1").build(),
+				new Payload(new JSONObject(claims)));
+		jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
+		return jws.serialize();
+	}
+
+	private void mockWebServer(String response) {
+		this.web.enqueue(new MockResponse().setResponseCode(200)
+				.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(response));
+	}
+
+	private void mockRestOperations(String response) {
+		RestOperations rest = this.spring.getContext().getBean(RestOperations.class);
+		HttpHeaders headers = new HttpHeaders();
+		headers.setContentType(MediaType.APPLICATION_JSON);
+		ResponseEntity entity = new ResponseEntity<>(response, headers, HttpStatus.OK);
+		when(rest.exchange(any(RequestEntity.class), eq(String.class))).thenReturn(entity);
+	}
+
+	private  T bean(Class beanClass) {
+		return this.spring.getContext().getBean(beanClass);
+	}
+
+	private  T verifyBean(Class beanClass) {
+		return verify(this.spring.getContext().getBean(beanClass));
+	}
+
+	private String json(String name) throws IOException {
+		return resource(name + ".json");
+	}
+
+	private String jwks(String name) throws IOException {
+		return resource(name + ".jwks");
+	}
+
+	private String token(String name) throws IOException {
+		return resource(name + ".token");
+	}
+
+	private String resource(String suffix) throws IOException {
+		String name = this.getClass().getSimpleName() + "-" + suffix;
+		ClassPathResource resource = new ClassPathResource(name, this.getClass());
+		try (BufferedReader reader = new BufferedReader(new FileReader(resource.getFile()))) {
+			return reader.lines().collect(Collectors.joining());
+		}
+	}
 
 	@EnableWebSecurity
 	static class DefaultConfig extends WebSecurityConfigurerAdapter {
@@ -2293,10 +2375,6 @@ public class OAuth2ResourceServerConfigurerTests {
 
 	}
 
-	private static  void registerMockBean(GenericApplicationContext context, String name, Class clazz) {
-		context.registerBean(name, clazz, () -> mock(clazz));
-	}
-
 	private static class BearerTokenRequestPostProcessor implements RequestPostProcessor {
 
 		private boolean asRequestParameter;
@@ -2326,84 +2404,4 @@ public class OAuth2ResourceServerConfigurerTests {
 
 	}
 
-	private static BearerTokenRequestPostProcessor bearerToken(String token) {
-		return new BearerTokenRequestPostProcessor(token);
-	}
-
-	private static ResultMatcher invalidRequestHeader(String message) {
-		return header().string(HttpHeaders.WWW_AUTHENTICATE,
-				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_request\", " + "error_description=\""),
-						new StringContains(message),
-						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
-	}
-
-	private static ResultMatcher invalidTokenHeader(String message) {
-		return header().string(HttpHeaders.WWW_AUTHENTICATE,
-				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_token\", " + "error_description=\""),
-						new StringContains(message),
-						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
-	}
-
-	private static ResultMatcher insufficientScopeHeader() {
-		return header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer " + "error=\"insufficient_scope\""
-				+ ", error_description=\"The request requires higher privileges than provided by the access token.\""
-				+ ", error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
-	}
-
-	private String jwkSet() {
-		return new JWKSet(new RSAKey.Builder(TestKeys.DEFAULT_PUBLIC_KEY).keyID("1").build()).toString();
-	}
-
-	private String jwtFromIssuer(String issuer) throws Exception {
-		Map claims = new HashMap<>();
-		claims.put(ISS, issuer);
-		claims.put(SUB, "test-subject");
-		claims.put("scope", "message:read");
-		JWSObject jws = new JWSObject(new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("1").build(),
-				new Payload(new JSONObject(claims)));
-		jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
-		return jws.serialize();
-	}
-
-	private void mockWebServer(String response) {
-		this.web.enqueue(new MockResponse().setResponseCode(200)
-				.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(response));
-	}
-
-	private void mockRestOperations(String response) {
-		RestOperations rest = this.spring.getContext().getBean(RestOperations.class);
-		HttpHeaders headers = new HttpHeaders();
-		headers.setContentType(MediaType.APPLICATION_JSON);
-		ResponseEntity entity = new ResponseEntity<>(response, headers, HttpStatus.OK);
-		when(rest.exchange(any(RequestEntity.class), eq(String.class))).thenReturn(entity);
-	}
-
-	private  T bean(Class beanClass) {
-		return this.spring.getContext().getBean(beanClass);
-	}
-
-	private  T verifyBean(Class beanClass) {
-		return verify(this.spring.getContext().getBean(beanClass));
-	}
-
-	private String json(String name) throws IOException {
-		return resource(name + ".json");
-	}
-
-	private String jwks(String name) throws IOException {
-		return resource(name + ".jwks");
-	}
-
-	private String token(String name) throws IOException {
-		return resource(name + ".token");
-	}
-
-	private String resource(String suffix) throws IOException {
-		String name = this.getClass().getSimpleName() + "-" + suffix;
-		ClassPathResource resource = new ClassPathResource(name, this.getClass());
-		try (BufferedReader reader = new BufferedReader(new FileReader(resource.getFile()))) {
-			return reader.lines().collect(Collectors.joining());
-		}
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
index ab6ff70dd8..f2882e78f0 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
@@ -83,35 +83,6 @@ public class OpenIDLoginConfigurerTests {
 		verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(OpenIDAuthenticationProvider.class));
 	}
 
-	@EnableWebSecurity
-	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
-
-		static ObjectPostProcessor objectPostProcessor;
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.openidLogin();
-			// @formatter:on
-		}
-
-		@Bean
-		static ObjectPostProcessor objectPostProcessor() {
-			return objectPostProcessor;
-		}
-
-	}
-
-	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
-
-		@Override
-		public  O postProcess(O object) {
-			return object;
-		}
-
-	}
-
 	@Test
 	public void openidLoginWhenInvokedTwiceThenUsesOriginalLoginPage() throws Exception {
 		this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
@@ -120,33 +91,6 @@ public class OpenIDLoginConfigurerTests {
 				.andExpect(redirectedUrl("http://localhost/login/custom"));
 	}
 
-	@EnableWebSecurity
-	static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
-			// @formatter:off
-			auth
-				.inMemoryAuthentication();
-			// @formatter:on
-		}
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.openidLogin()
-					.loginPage("/login/custom")
-					.and()
-				.openidLogin();
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception {
 		this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire();
@@ -155,26 +99,6 @@ public class OpenIDLoginConfigurerTests {
 				.andExpect(redirectedUrl("http://localhost/login/custom"));
 	}
 
-	@EnableWebSecurity
-	static class OpenIdLoginPageInLambdaConfig extends WebSecurityConfigurerAdapter {
-
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-			// @formatter:off
-			http
-				.authorizeRequests(authorizeRequests ->
-					authorizeRequests
-						.anyRequest().authenticated()
-				)
-				.openidLogin(openIdLogin ->
-					openIdLogin
-						.loginPage("/login/custom")
-				);
-			// @formatter:on
-		}
-
-	}
-
 	@Test
 	public void requestWhenAttributeExchangeConfiguredThenFetchAttributesMatchAttributeList() throws Exception {
 		OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
@@ -213,6 +137,113 @@ public class OpenIDLoginConfigurerTests {
 		}
 	}
 
+	@Test
+	public void requestWhenAttributeNameNotSpecifiedThenAttributeNameDefaulted() throws Exception {
+		OpenIdAttributesNullNameConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
+		AuthRequest mockAuthRequest = mock(AuthRequest.class);
+		DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
+		when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl");
+		when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.associate(any())).thenReturn(mockDiscoveryInformation);
+		when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(),
+				any())).thenReturn(mockAuthRequest);
+		this.spring.register(OpenIdAttributesNullNameConfig.class).autowire();
+
+		try (MockWebServer server = new MockWebServer()) {
+			String endpoint = server.url("/").toString();
+
+			server.enqueue(new MockResponse().addHeader(YADIS_XRDS_LOCATION, endpoint));
+			server.enqueue(new MockResponse()
+					.setBody(String.format("%s", endpoint)));
+
+			MvcResult mvcResult = this.mvc.perform(
+					get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
+					.andExpect(status().isFound()).andReturn();
+
+			Object attributeObject = mvcResult.getRequest().getSession()
+					.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
+			assertThat(attributeObject).isInstanceOf(List.class);
+			List attributeList = (List) attributeObject;
+			assertThat(attributeList).hasSize(1);
+			assertThat(attributeList.get(0).getName()).isEqualTo("default-attribute");
+		}
+	}
+
+	@EnableWebSecurity
+	static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
+
+		static ObjectPostProcessor objectPostProcessor;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.openidLogin();
+			// @formatter:on
+		}
+
+		@Bean
+		static ObjectPostProcessor objectPostProcessor() {
+			return objectPostProcessor;
+		}
+
+	}
+
+	static class ReflectingObjectPostProcessor implements ObjectPostProcessor {
+
+		@Override
+		public  O postProcess(O object) {
+			return object;
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication();
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.openidLogin()
+					.loginPage("/login/custom")
+					.and()
+				.openidLogin();
+			// @formatter:on
+		}
+
+	}
+
+	@EnableWebSecurity
+	static class OpenIdLoginPageInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.openidLogin(openIdLogin ->
+					openIdLogin
+						.loginPage("/login/custom")
+				);
+			// @formatter:on
+		}
+
+	}
+
 	@EnableWebSecurity
 	static class OpenIdAttributesInLambdaConfig extends WebSecurityConfigurerAdapter {
 
@@ -251,37 +282,6 @@ public class OpenIDLoginConfigurerTests {
 
 	}
 
-	@Test
-	public void requestWhenAttributeNameNotSpecifiedThenAttributeNameDefaulted() throws Exception {
-		OpenIdAttributesNullNameConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
-		AuthRequest mockAuthRequest = mock(AuthRequest.class);
-		DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
-		when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl");
-		when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.associate(any())).thenReturn(mockDiscoveryInformation);
-		when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(),
-				any())).thenReturn(mockAuthRequest);
-		this.spring.register(OpenIdAttributesNullNameConfig.class).autowire();
-
-		try (MockWebServer server = new MockWebServer()) {
-			String endpoint = server.url("/").toString();
-
-			server.enqueue(new MockResponse().addHeader(YADIS_XRDS_LOCATION, endpoint));
-			server.enqueue(new MockResponse()
-					.setBody(String.format("%s", endpoint)));
-
-			MvcResult mvcResult = this.mvc.perform(
-					get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
-					.andExpect(status().isFound()).andReturn();
-
-			Object attributeObject = mvcResult.getRequest().getSession()
-					.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
-			assertThat(attributeObject).isInstanceOf(List.class);
-			List attributeList = (List) attributeObject;
-			assertThat(attributeList).hasSize(1);
-			assertThat(attributeList.get(0).getName()).isEqualTo("default-attribute");
-		}
-	}
-
 	@EnableWebSecurity
 	static class OpenIdAttributesNullNameConfig extends WebSecurityConfigurerAdapter {
 
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java
index de8bd7924c..d387b12037 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java
@@ -241,6 +241,44 @@ public class Saml2LoginConfigurerTests {
 				.hasToString(expected);
 	}
 
+	private static org.apache.commons.codec.binary.Base64 BASE64 = new org.apache.commons.codec.binary.Base64(0,
+			new byte[] { '\n' });
+
+	private static byte[] samlDecode(String s) {
+		return BASE64.decode(s);
+	}
+
+	private static String samlInflate(byte[] b) {
+		try {
+			ByteArrayOutputStream out = new ByteArrayOutputStream();
+			InflaterOutputStream iout = new InflaterOutputStream(out, new Inflater(true));
+			iout.write(b);
+			iout.finish();
+			return new String(out.toByteArray(), UTF_8);
+		}
+		catch (IOException e) {
+			throw new Saml2Exception("Unable to inflate string", e);
+		}
+	}
+
+	private static AuthenticationManager getAuthenticationManagerMock(String role) {
+		return new AuthenticationManager() {
+
+			@Override
+			public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+				if (!supports(authentication.getClass())) {
+					throw new AuthenticationServiceException("not supported");
+				}
+				return new Saml2Authentication(() -> "auth principal", "saml2 response",
+						Collections.singletonList(new SimpleGrantedAuthority(role)));
+			}
+
+			public boolean supports(Class authentication) {
+				return authentication.isAssignableFrom(Saml2AuthenticationToken.class);
+			}
+		};
+	}
+
 	@EnableWebSecurity
 	@Import(Saml2LoginConfigBeans.class)
 	static class Saml2LoginConfigWithCustomAuthenticationManager extends WebSecurityConfigurerAdapter {
@@ -339,24 +377,6 @@ public class Saml2LoginConfigurerTests {
 
 	}
 
-	private static AuthenticationManager getAuthenticationManagerMock(String role) {
-		return new AuthenticationManager() {
-
-			@Override
-			public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-				if (!supports(authentication.getClass())) {
-					throw new AuthenticationServiceException("not supported");
-				}
-				return new Saml2Authentication(() -> "auth principal", "saml2 response",
-						Collections.singletonList(new SimpleGrantedAuthority(role)));
-			}
-
-			public boolean supports(Class authentication) {
-				return authentication.isAssignableFrom(Saml2AuthenticationToken.class);
-			}
-		};
-	}
-
 	static class Saml2LoginConfigBeans {
 
 		@Bean
@@ -373,24 +393,4 @@ public class Saml2LoginConfigurerTests {
 
 	}
 
-	private static org.apache.commons.codec.binary.Base64 BASE64 = new org.apache.commons.codec.binary.Base64(0,
-			new byte[] { '\n' });
-
-	private static byte[] samlDecode(String s) {
-		return BASE64.decode(s);
-	}
-
-	private static String samlInflate(byte[] b) {
-		try {
-			ByteArrayOutputStream out = new ByteArrayOutputStream();
-			InflaterOutputStream iout = new InflaterOutputStream(out, new Inflater(true));
-			iout.write(b);
-			iout.finish();
-			return new String(out.toByteArray(), UTF_8);
-		}
-		catch (IOException e) {
-			throw new Saml2Exception("Unable to inflate string", e);
-		}
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java
index 5f01efd285..fdd1461eeb 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java
@@ -164,12 +164,6 @@ public class EnableWebFluxSecurityTests {
 		assertThat(rdvp).isNotNull();
 	}
 
-	@EnableWebFluxSecurity
-	@Import(ReactiveAuthenticationTestConfiguration.class)
-	static class Config {
-
-	}
-
 	@Test
 	public void passwordEncoderBeanIsUsed() {
 		this.spring.register(CustomPasswordEncoderConfig.class).autowire();
@@ -186,22 +180,6 @@ public class EnableWebFluxSecurityTests {
 				.consumeWith(result -> assertThat(result.getResponseBody()).isEqualTo("user"));
 	}
 
-	@EnableWebFluxSecurity
-	static class CustomPasswordEncoderConfig {
-
-		@Bean
-		public ReactiveUserDetailsService userDetailsService(PasswordEncoder encoder) {
-			return new MapReactiveUserDetailsService(
-					User.withUsername("user").password(encoder.encode("password")).roles("USER").build());
-		}
-
-		@Bean
-		public static PasswordEncoder passwordEncoder() {
-			return new BCryptPasswordEncoder();
-		}
-
-	}
-
 	@Test
 	public void passwordUpdateManagerUsed() {
 		this.spring.register(MapReactiveUserDetailsServiceConfig.class).autowire();
@@ -213,22 +191,6 @@ public class EnableWebFluxSecurityTests {
 		assertThat(users.findByUsername("user").block().getPassword()).startsWith("{bcrypt}");
 	}
 
-	@EnableWebFluxSecurity
-	static class MapReactiveUserDetailsServiceConfig {
-
-		@Bean
-		public MapReactiveUserDetailsService userDetailsService() {
-			// @formatter:off
-			return new MapReactiveUserDetailsService(User.withUsername("user")
-					.password("{noop}password")
-					.roles("USER")
-					.build()
-			// @formatter:on
-			);
-		}
-
-	}
-
 	@Test
 	public void formLoginWorks() {
 		this.spring.register(Config.class).autowire();
@@ -254,6 +216,87 @@ public class EnableWebFluxSecurityTests {
 		client.get().uri("/test").exchange().expectStatus().isOk();
 	}
 
+	@Test
+	@WithMockUser
+	public void authenticationPrincipalArgumentResolverWhenSpelThenWorks() {
+		this.spring.register(AuthenticationPrincipalConfig.class).autowire();
+
+		WebTestClient client = WebTestClient.bindToApplicationContext(this.spring.getContext()).build();
+
+		client.get().uri("/spel").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("user");
+	}
+
+	private static DataBuffer toDataBuffer(String body) {
+		DataBuffer buffer = new DefaultDataBufferFactory().allocateBuffer();
+		buffer.write(body.getBytes(StandardCharsets.UTF_8));
+		return buffer;
+	}
+
+	@Test
+	public void enableWebFluxSecurityWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
+		this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
+
+		Child childBean = this.spring.getContext().getBean(Child.class);
+		Parent parentBean = this.spring.getContext().getBean(Parent.class);
+
+		assertThat(parentBean.getChild()).isSameAs(childBean);
+	}
+
+	@Test
+	public void enableWebFluxSecurityWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
+		this.spring.register(BeanProxyDisabledConfig.class).autowire();
+
+		Child childBean = this.spring.getContext().getBean(Child.class);
+		Parent parentBean = this.spring.getContext().getBean(Parent.class);
+
+		assertThat(parentBean.getChild()).isNotSameAs(childBean);
+	}
+
+	@Test
+	// gh-8596
+	public void resolveAuthenticationPrincipalArgumentResolverFirstDoesNotCauseBeanCurrentlyInCreationException() {
+		this.spring.register(EnableWebFluxSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
+				DelegatingWebFluxConfiguration.class).autowire();
+	}
+
+	@EnableWebFluxSecurity
+	@Import(ReactiveAuthenticationTestConfiguration.class)
+	static class Config {
+
+	}
+
+	@EnableWebFluxSecurity
+	static class CustomPasswordEncoderConfig {
+
+		@Bean
+		public ReactiveUserDetailsService userDetailsService(PasswordEncoder encoder) {
+			return new MapReactiveUserDetailsService(
+					User.withUsername("user").password(encoder.encode("password")).roles("USER").build());
+		}
+
+		@Bean
+		public static PasswordEncoder passwordEncoder() {
+			return new BCryptPasswordEncoder();
+		}
+
+	}
+
+	@EnableWebFluxSecurity
+	static class MapReactiveUserDetailsServiceConfig {
+
+		@Bean
+		public MapReactiveUserDetailsService userDetailsService() {
+			// @formatter:off
+			return new MapReactiveUserDetailsService(User.withUsername("user")
+					.password("{noop}password")
+					.roles("USER")
+					.build()
+			// @formatter:on
+			);
+		}
+
+	}
+
 	@EnableWebFluxSecurity
 	@Import(ReactiveAuthenticationTestConfiguration.class)
 	static class MultiSecurityHttpConfig {
@@ -273,16 +316,6 @@ public class EnableWebFluxSecurityTests {
 
 	}
 
-	@Test
-	@WithMockUser
-	public void authenticationPrincipalArgumentResolverWhenSpelThenWorks() {
-		this.spring.register(AuthenticationPrincipalConfig.class).autowire();
-
-		WebTestClient client = WebTestClient.bindToApplicationContext(this.spring.getContext()).build();
-
-		client.get().uri("/spel").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("user");
-	}
-
 	@EnableWebFluxSecurity
 	@EnableWebFlux
 	@Import(ReactiveAuthenticationTestConfiguration.class)
@@ -313,22 +346,6 @@ public class EnableWebFluxSecurityTests {
 
 	}
 
-	private static DataBuffer toDataBuffer(String body) {
-		DataBuffer buffer = new DefaultDataBufferFactory().allocateBuffer();
-		buffer.write(body.getBytes(StandardCharsets.UTF_8));
-		return buffer;
-	}
-
-	@Test
-	public void enableWebFluxSecurityWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
-		this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
-
-		Child childBean = this.spring.getContext().getBean(Child.class);
-		Parent parentBean = this.spring.getContext().getBean(Parent.class);
-
-		assertThat(parentBean.getChild()).isSameAs(childBean);
-	}
-
 	@EnableWebFluxSecurity
 	@Import(ReactiveAuthenticationTestConfiguration.class)
 	static class BeanProxyEnabledByDefaultConfig {
@@ -345,16 +362,6 @@ public class EnableWebFluxSecurityTests {
 
 	}
 
-	@Test
-	public void enableWebFluxSecurityWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
-		this.spring.register(BeanProxyDisabledConfig.class).autowire();
-
-		Child childBean = this.spring.getContext().getBean(Child.class);
-		Parent parentBean = this.spring.getContext().getBean(Parent.class);
-
-		assertThat(parentBean.getChild()).isNotSameAs(childBean);
-	}
-
 	@Configuration(proxyBeanMethods = false)
 	@EnableWebFluxSecurity
 	@Import(ReactiveAuthenticationTestConfiguration.class)
@@ -393,13 +400,6 @@ public class EnableWebFluxSecurityTests {
 
 	}
 
-	@Test
-	// gh-8596
-	public void resolveAuthenticationPrincipalArgumentResolverFirstDoesNotCauseBeanCurrentlyInCreationException() {
-		this.spring.register(EnableWebFluxSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
-				DelegatingWebFluxConfiguration.class).autowire();
-	}
-
 	@EnableWebFluxSecurity
 	@Configuration(proxyBeanMethods = false)
 	static class EnableWebFluxSecurityConfiguration {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java
index 9d73774461..8511a04d73 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java
@@ -272,43 +272,6 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
 		}
 	}
 
-	@Configuration
-	@EnableWebSocketMessageBroker
-	@Import(SyncExecutorConfig.class)
-	static class MsmsRegistryCustomPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
-
-		// @formatter:off
-		@Override
-		public void registerStompEndpoints(StompEndpointRegistry registry) {
-			registry
-				.addEndpoint("/other")
-				.setHandshakeHandler(testHandshakeHandler());
-		}
-		// @formatter:on
-
-		// @formatter:off
-		@Override
-		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
-			messages
-				.simpDestMatchers("/app/a.*").permitAll()
-				.anyMessage().denyAll();
-		}
-		// @formatter:on
-
-		@Override
-		public void configureMessageBroker(MessageBrokerRegistry registry) {
-			registry.setPathMatcher(new AntPathMatcher("."));
-			registry.enableSimpleBroker("/queue/", "/topic/");
-			registry.setApplicationDestinationPrefixes("/app");
-		}
-
-		@Bean
-		public TestHandshakeHandler testHandshakeHandler() {
-			return new TestHandshakeHandler();
-		}
-
-	}
-
 	@Test
 	public void overrideMsmsRegistryCustomPatternMatcher() {
 		loadConfig(OverrideMsmsRegistryCustomPatternMatcherConfig.class);
@@ -324,45 +287,6 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
 		}
 	}
 
-	@Configuration
-	@EnableWebSocketMessageBroker
-	@Import(SyncExecutorConfig.class)
-	static class OverrideMsmsRegistryCustomPatternMatcherConfig
-			extends AbstractSecurityWebSocketMessageBrokerConfigurer {
-
-		// @formatter:off
-		@Override
-		public void registerStompEndpoints(StompEndpointRegistry registry) {
-			registry
-				.addEndpoint("/other")
-				.setHandshakeHandler(testHandshakeHandler());
-		}
-		// @formatter:on
-
-		// @formatter:off
-		@Override
-		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
-			messages
-				.simpDestPathMatcher(new AntPathMatcher())
-				.simpDestMatchers("/app/a/*").permitAll()
-				.anyMessage().denyAll();
-		}
-		// @formatter:on
-
-		@Override
-		public void configureMessageBroker(MessageBrokerRegistry registry) {
-			registry.setPathMatcher(new AntPathMatcher("."));
-			registry.enableSimpleBroker("/queue/", "/topic/");
-			registry.setApplicationDestinationPrefixes("/app");
-		}
-
-		@Bean
-		public TestHandshakeHandler testHandshakeHandler() {
-			return new TestHandshakeHandler();
-		}
-
-	}
-
 	@Test
 	public void defaultPatternMatcher() {
 		loadConfig(DefaultPatternMatcherConfig.class);
@@ -378,42 +302,6 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
 		}
 	}
 
-	@Configuration
-	@EnableWebSocketMessageBroker
-	@Import(SyncExecutorConfig.class)
-	static class DefaultPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
-
-		// @formatter:off
-		@Override
-		public void registerStompEndpoints(StompEndpointRegistry registry) {
-			registry
-				.addEndpoint("/other")
-				.setHandshakeHandler(testHandshakeHandler());
-		}
-		// @formatter:on
-
-		// @formatter:off
-		@Override
-		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
-			messages
-				.simpDestMatchers("/app/a/*").permitAll()
-				.anyMessage().denyAll();
-		}
-		// @formatter:on
-
-		@Override
-		public void configureMessageBroker(MessageBrokerRegistry registry) {
-			registry.enableSimpleBroker("/queue/", "/topic/");
-			registry.setApplicationDestinationPrefixes("/app");
-		}
-
-		@Bean
-		public TestHandshakeHandler testHandshakeHandler() {
-			return new TestHandshakeHandler();
-		}
-
-	}
-
 	@Test
 	public void customExpression() {
 		loadConfig(CustomExpressionConfig.class);
@@ -464,57 +352,6 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
 		assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()).contains(inboundChannelSecurity);
 	}
 
-	@Configuration
-	@EnableWebSocketMessageBroker
-	@Import(SyncExecutorConfig.class)
-	static class CustomExpressionConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
-
-		// @formatter:off
-		@Override
-		public void registerStompEndpoints(StompEndpointRegistry registry) {
-			registry
-				.addEndpoint("/other")
-				.setHandshakeHandler(testHandshakeHandler());
-		}
-		// @formatter:on
-
-		// @formatter:off
-		@Override
-		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
-			messages
-				.anyMessage().access("denyRob()");
-		}
-		// @formatter:on
-
-		@Bean
-		public static SecurityExpressionHandler> messageSecurityExpressionHandler() {
-			return new DefaultMessageSecurityExpressionHandler() {
-				@Override
-				protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
-						Message invocation) {
-					return new MessageSecurityExpressionRoot(authentication, invocation) {
-						public boolean denyRob() {
-							Authentication auth = getAuthentication();
-							return auth != null && !"rob".equals(auth.getName());
-						}
-					};
-				}
-			};
-		}
-
-		@Override
-		public void configureMessageBroker(MessageBrokerRegistry registry) {
-			registry.enableSimpleBroker("/queue/", "/topic/");
-			registry.setApplicationDestinationPrefixes("/app");
-		}
-
-		@Bean
-		public TestHandshakeHandler testHandshakeHandler() {
-			return new TestHandshakeHandler();
-		}
-
-	}
-
 	private void assertHandshake(HttpServletRequest request) {
 		TestHandshakeHandler handshakeHandler = this.context.getBean(TestHandshakeHandler.class);
 		assertThat(handshakeHandler.attributes.get(CsrfToken.class.getName())).isSameAs(this.token);
@@ -572,6 +409,169 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
 		this.context.refresh();
 	}
 
+	@Configuration
+	@EnableWebSocketMessageBroker
+	@Import(SyncExecutorConfig.class)
+	static class MsmsRegistryCustomPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
+
+		// @formatter:off
+		@Override
+		public void registerStompEndpoints(StompEndpointRegistry registry) {
+			registry
+				.addEndpoint("/other")
+				.setHandshakeHandler(testHandshakeHandler());
+		}
+		// @formatter:on
+
+		// @formatter:off
+		@Override
+		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
+			messages
+				.simpDestMatchers("/app/a.*").permitAll()
+				.anyMessage().denyAll();
+		}
+		// @formatter:on
+
+		@Override
+		public void configureMessageBroker(MessageBrokerRegistry registry) {
+			registry.setPathMatcher(new AntPathMatcher("."));
+			registry.enableSimpleBroker("/queue/", "/topic/");
+			registry.setApplicationDestinationPrefixes("/app");
+		}
+
+		@Bean
+		public TestHandshakeHandler testHandshakeHandler() {
+			return new TestHandshakeHandler();
+		}
+
+	}
+
+	@Configuration
+	@EnableWebSocketMessageBroker
+	@Import(SyncExecutorConfig.class)
+	static class OverrideMsmsRegistryCustomPatternMatcherConfig
+			extends AbstractSecurityWebSocketMessageBrokerConfigurer {
+
+		// @formatter:off
+		@Override
+		public void registerStompEndpoints(StompEndpointRegistry registry) {
+			registry
+				.addEndpoint("/other")
+				.setHandshakeHandler(testHandshakeHandler());
+		}
+		// @formatter:on
+
+		// @formatter:off
+		@Override
+		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
+			messages
+				.simpDestPathMatcher(new AntPathMatcher())
+				.simpDestMatchers("/app/a/*").permitAll()
+				.anyMessage().denyAll();
+		}
+		// @formatter:on
+
+		@Override
+		public void configureMessageBroker(MessageBrokerRegistry registry) {
+			registry.setPathMatcher(new AntPathMatcher("."));
+			registry.enableSimpleBroker("/queue/", "/topic/");
+			registry.setApplicationDestinationPrefixes("/app");
+		}
+
+		@Bean
+		public TestHandshakeHandler testHandshakeHandler() {
+			return new TestHandshakeHandler();
+		}
+
+	}
+
+	@Configuration
+	@EnableWebSocketMessageBroker
+	@Import(SyncExecutorConfig.class)
+	static class DefaultPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
+
+		// @formatter:off
+		@Override
+		public void registerStompEndpoints(StompEndpointRegistry registry) {
+			registry
+				.addEndpoint("/other")
+				.setHandshakeHandler(testHandshakeHandler());
+		}
+		// @formatter:on
+
+		// @formatter:off
+		@Override
+		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
+			messages
+				.simpDestMatchers("/app/a/*").permitAll()
+				.anyMessage().denyAll();
+		}
+		// @formatter:on
+
+		@Override
+		public void configureMessageBroker(MessageBrokerRegistry registry) {
+			registry.enableSimpleBroker("/queue/", "/topic/");
+			registry.setApplicationDestinationPrefixes("/app");
+		}
+
+		@Bean
+		public TestHandshakeHandler testHandshakeHandler() {
+			return new TestHandshakeHandler();
+		}
+
+	}
+
+	@Configuration
+	@EnableWebSocketMessageBroker
+	@Import(SyncExecutorConfig.class)
+	static class CustomExpressionConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
+
+		// @formatter:off
+		@Override
+		public void registerStompEndpoints(StompEndpointRegistry registry) {
+			registry
+				.addEndpoint("/other")
+				.setHandshakeHandler(testHandshakeHandler());
+		}
+		// @formatter:on
+
+		// @formatter:off
+		@Override
+		protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
+			messages
+				.anyMessage().access("denyRob()");
+		}
+		// @formatter:on
+
+		@Bean
+		public static SecurityExpressionHandler> messageSecurityExpressionHandler() {
+			return new DefaultMessageSecurityExpressionHandler() {
+				@Override
+				protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
+						Message invocation) {
+					return new MessageSecurityExpressionRoot(authentication, invocation) {
+						public boolean denyRob() {
+							Authentication auth = getAuthentication();
+							return auth != null && !"rob".equals(auth.getName());
+						}
+					};
+				}
+			};
+		}
+
+		@Override
+		public void configureMessageBroker(MessageBrokerRegistry registry) {
+			registry.enableSimpleBroker("/queue/", "/topic/");
+			registry.setApplicationDestinationPrefixes("/app");
+		}
+
+		@Bean
+		public TestHandshakeHandler testHandshakeHandler() {
+			return new TestHandshakeHandler();
+		}
+
+	}
+
 	@Controller
 	static class MyController {
 
diff --git a/config/src/test/java/org/springframework/security/config/http/CsrfConfigTests.java b/config/src/test/java/org/springframework/security/config/http/CsrfConfigTests.java
index bab0a7e840..edff3fe164 100644
--- a/config/src/test/java/org/springframework/security/config/http/CsrfConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/CsrfConfigTests.java
@@ -417,6 +417,27 @@ public class CsrfConfigTests {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
 
+	ResultMatcher csrfChanged(MvcResult first) {
+		return (second) -> {
+			assertThat(first).isNotNull();
+			assertThat(second).isNotNull();
+			assertThat(first.getResponse().getContentAsString())
+					.isNotEqualTo(second.getResponse().getContentAsString());
+		};
+	}
+
+	ResultMatcher csrfCreated() {
+		return new CsrfCreatedResultMatcher();
+	}
+
+	ResultMatcher csrfInHeader() {
+		return new CsrfReturnedResultMatcher(result -> result.getResponse().getHeader("X-CSRF-TOKEN"));
+	}
+
+	ResultMatcher csrfInBody() {
+		return new CsrfReturnedResultMatcher(result -> result.getResponse().getContentAsString());
+	}
+
 	@Controller
 	public static class RootController {
 
@@ -458,27 +479,6 @@ public class CsrfConfigTests {
 
 	}
 
-	ResultMatcher csrfChanged(MvcResult first) {
-		return (second) -> {
-			assertThat(first).isNotNull();
-			assertThat(second).isNotNull();
-			assertThat(first.getResponse().getContentAsString())
-					.isNotEqualTo(second.getResponse().getContentAsString());
-		};
-	}
-
-	ResultMatcher csrfCreated() {
-		return new CsrfCreatedResultMatcher();
-	}
-
-	ResultMatcher csrfInHeader() {
-		return new CsrfReturnedResultMatcher(result -> result.getResponse().getHeader("X-CSRF-TOKEN"));
-	}
-
-	ResultMatcher csrfInBody() {
-		return new CsrfReturnedResultMatcher(result -> result.getResponse().getContentAsString());
-	}
-
 	@FunctionalInterface
 	interface ExceptionalFunction {
 
diff --git a/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java b/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java
index 190c0d66d7..4adaebc234 100644
--- a/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java
@@ -175,6 +175,24 @@ public class FormLoginConfigTests {
 				.andExpect(redirectedUrl("/login?error"));
 	}
 
+	private Filter getFilter(ApplicationContext context, Class filterClass) {
+		FilterChainProxy filterChain = context.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class);
+
+		List filters = filterChain.getFilters("/any");
+
+		for (Filter filter : filters) {
+			if (filter.getClass() == filterClass) {
+				return filter;
+			}
+		}
+
+		return null;
+	}
+
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@RestController
 	public static class LoginController {
 
@@ -204,22 +222,4 @@ public class FormLoginConfigTests {
 
 	}
 
-	private Filter getFilter(ApplicationContext context, Class filterClass) {
-		FilterChainProxy filterChain = context.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class);
-
-		List filters = filterChain.getFilters("/any");
-
-		for (Filter filter : filters) {
-			if (filter.getClass() == filterClass) {
-				return filter;
-			}
-		}
-
-		return null;
-	}
-
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java b/config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java
index 2f9fcd22de..3cd2f3be8b 100644
--- a/config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java
@@ -73,6 +73,10 @@ public class HttpConfigTests {
 		assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/login");
 	}
 
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	private static class EncodeUrlDenyingHttpServletResponseWrapper extends HttpServletResponseWrapper {
 
 		EncodeUrlDenyingHttpServletResponseWrapper(HttpServletResponse response) {
@@ -101,8 +105,4 @@ public class HttpConfigTests {
 
 	}
 
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/HttpCorsConfigTests.java b/config/src/test/java/org/springframework/security/config/http/HttpCorsConfigTests.java
index 6f0beba0a0..a51ff6d242 100644
--- a/config/src/test/java/org/springframework/security/config/http/HttpCorsConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/HttpCorsConfigTests.java
@@ -99,29 +99,6 @@ public class HttpCorsConfigTests {
 				.andExpect(status().isOk());
 	}
 
-	@RestController
-	@CrossOrigin(methods = { RequestMethod.GET, RequestMethod.POST })
-	static class CorsController {
-
-		@RequestMapping("/")
-		String hello() {
-			return "Hello";
-		}
-
-	}
-
-	static class MyCorsConfigurationSource extends UrlBasedCorsConfigurationSource {
-
-		MyCorsConfigurationSource() {
-			CorsConfiguration configuration = new CorsConfiguration();
-			configuration.setAllowedOrigins(Arrays.asList("*"));
-			configuration.setAllowedMethods(Arrays.asList(RequestMethod.GET.name(), RequestMethod.POST.name()));
-
-			super.registerCorsConfiguration("/**", configuration);
-		}
-
-	}
-
 	private String xml(String configName) {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
@@ -154,4 +131,27 @@ public class HttpCorsConfigTests {
 		};
 	}
 
+	@RestController
+	@CrossOrigin(methods = { RequestMethod.GET, RequestMethod.POST })
+	static class CorsController {
+
+		@RequestMapping("/")
+		String hello() {
+			return "Hello";
+		}
+
+	}
+
+	static class MyCorsConfigurationSource extends UrlBasedCorsConfigurationSource {
+
+		MyCorsConfigurationSource() {
+			CorsConfiguration configuration = new CorsConfiguration();
+			configuration.setAllowedOrigins(Arrays.asList("*"));
+			configuration.setAllowedMethods(Arrays.asList(RequestMethod.GET.name(), RequestMethod.POST.name()));
+
+			super.registerCorsConfiguration("/**", configuration);
+		}
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java b/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java
index ad543ee1e3..4bc4ae8846 100644
--- a/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/HttpHeadersConfigTests.java
@@ -659,16 +659,6 @@ public class HttpHeadersConfigTests {
 				.andExpect(header().string("Referrer-Policy", "same-origin"));
 	}
 
-	@RestController
-	public static class SimpleController {
-
-		@GetMapping("/")
-		public String ok() {
-			return "ok";
-		}
-
-	}
-
 	private static ResultMatcher includesDefaults() {
 		return includes(defaultHeaders);
 	}
@@ -711,4 +701,14 @@ public class HttpHeadersConfigTests {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
 
+	@RestController
+	public static class SimpleController {
+
+		@GetMapping("/")
+		public String ok() {
+			return "ok";
+		}
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java
index 3c94ae6f00..565bea71d1 100644
--- a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java
@@ -209,6 +209,20 @@ public class InterceptUrlConfigTests {
 				.isInstanceOf(BeanDefinitionParsingException.class);
 	}
 
+	private MockServletContext mockServletContext(String servletPath) {
+		MockServletContext servletContext = spy(new MockServletContext());
+		final ServletRegistration registration = mock(ServletRegistration.class);
+		when(registration.getMappings()).thenReturn(Collections.singleton(servletPath));
+		Answer> answer = invocation -> Collections.singletonMap("spring",
+				registration);
+		when(servletContext.getServletRegistrations()).thenAnswer(answer);
+		return servletContext;
+	}
+
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@RestController
 	static class PathController {
 
@@ -232,18 +246,4 @@ public class InterceptUrlConfigTests {
 
 	}
 
-	private MockServletContext mockServletContext(String servletPath) {
-		MockServletContext servletContext = spy(new MockServletContext());
-		final ServletRegistration registration = mock(ServletRegistration.class);
-		when(registration.getMappings()).thenReturn(Collections.singleton(servletPath));
-		Answer> answer = invocation -> Collections.singletonMap("spring",
-				registration);
-		when(servletContext.getServletRegistrations()).thenAnswer(answer);
-		return servletContext;
-	}
-
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java b/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java
index 2c59e39123..604880a82a 100644
--- a/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java
@@ -694,6 +694,59 @@ public class MiscHttpConfigTests {
 				.andExpect(redirectedUrl("https://localhost:9443/protected"));
 	}
 
+	private void redirectLogsTo(OutputStream os, Class clazz) {
+		Logger logger = (Logger) LoggerFactory.getLogger(clazz);
+		Appender appender = mock(Appender.class);
+		when(appender.isStarted()).thenReturn(true);
+		doAnswer(writeTo(os)).when(appender).doAppend(any(ILoggingEvent.class));
+		logger.addAppender(appender);
+	}
+
+	private Answer writeTo(OutputStream os) {
+		return invocation -> {
+			os.write(invocation.getArgument(0).toString().getBytes());
+			return null;
+		};
+	}
+
+	private void assertThatFiltersMatchExpectedAutoConfigList() {
+		assertThatFiltersMatchExpectedAutoConfigList("/");
+	}
+
+	private void assertThatFiltersMatchExpectedAutoConfigList(String url) {
+		Iterator filters = getFilters(url).iterator();
+
+		assertThat(filters.next()).isInstanceOf(SecurityContextPersistenceFilter.class);
+		assertThat(filters.next()).isInstanceOf(WebAsyncManagerIntegrationFilter.class);
+		assertThat(filters.next()).isInstanceOf(HeaderWriterFilter.class);
+		assertThat(filters.next()).isInstanceOf(CsrfFilter.class);
+		assertThat(filters.next()).isInstanceOf(LogoutFilter.class);
+		assertThat(filters.next()).isInstanceOf(UsernamePasswordAuthenticationFilter.class);
+		assertThat(filters.next()).isInstanceOf(DefaultLoginPageGeneratingFilter.class);
+		assertThat(filters.next()).isInstanceOf(DefaultLogoutPageGeneratingFilter.class);
+		assertThat(filters.next()).isInstanceOf(BasicAuthenticationFilter.class);
+		assertThat(filters.next()).isInstanceOf(RequestCacheAwareFilter.class);
+		assertThat(filters.next()).isInstanceOf(SecurityContextHolderAwareRequestFilter.class);
+		assertThat(filters.next()).isInstanceOf(AnonymousAuthenticationFilter.class);
+		assertThat(filters.next()).isInstanceOf(SessionManagementFilter.class);
+		assertThat(filters.next()).isInstanceOf(ExceptionTranslationFilter.class);
+		assertThat(filters.next()).isInstanceOf(FilterSecurityInterceptor.class)
+				.hasFieldOrPropertyWithValue("observeOncePerRequest", true);
+	}
+
+	private  T getFilter(Class filterClass) {
+		return (T) getFilters("/").stream().filter(filterClass::isInstance).findFirst().orElse(null);
+	}
+
+	private List getFilters(String url) {
+		FilterChainProxy proxy = this.spring.getContext().getBean(FilterChainProxy.class);
+		return proxy.getFilters(url);
+	}
+
+	private static String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@RestController
 	static class BasicController {
 
@@ -847,57 +900,4 @@ public class MiscHttpConfigTests {
 
 	}
 
-	private void redirectLogsTo(OutputStream os, Class clazz) {
-		Logger logger = (Logger) LoggerFactory.getLogger(clazz);
-		Appender appender = mock(Appender.class);
-		when(appender.isStarted()).thenReturn(true);
-		doAnswer(writeTo(os)).when(appender).doAppend(any(ILoggingEvent.class));
-		logger.addAppender(appender);
-	}
-
-	private Answer writeTo(OutputStream os) {
-		return invocation -> {
-			os.write(invocation.getArgument(0).toString().getBytes());
-			return null;
-		};
-	}
-
-	private void assertThatFiltersMatchExpectedAutoConfigList() {
-		assertThatFiltersMatchExpectedAutoConfigList("/");
-	}
-
-	private void assertThatFiltersMatchExpectedAutoConfigList(String url) {
-		Iterator filters = getFilters(url).iterator();
-
-		assertThat(filters.next()).isInstanceOf(SecurityContextPersistenceFilter.class);
-		assertThat(filters.next()).isInstanceOf(WebAsyncManagerIntegrationFilter.class);
-		assertThat(filters.next()).isInstanceOf(HeaderWriterFilter.class);
-		assertThat(filters.next()).isInstanceOf(CsrfFilter.class);
-		assertThat(filters.next()).isInstanceOf(LogoutFilter.class);
-		assertThat(filters.next()).isInstanceOf(UsernamePasswordAuthenticationFilter.class);
-		assertThat(filters.next()).isInstanceOf(DefaultLoginPageGeneratingFilter.class);
-		assertThat(filters.next()).isInstanceOf(DefaultLogoutPageGeneratingFilter.class);
-		assertThat(filters.next()).isInstanceOf(BasicAuthenticationFilter.class);
-		assertThat(filters.next()).isInstanceOf(RequestCacheAwareFilter.class);
-		assertThat(filters.next()).isInstanceOf(SecurityContextHolderAwareRequestFilter.class);
-		assertThat(filters.next()).isInstanceOf(AnonymousAuthenticationFilter.class);
-		assertThat(filters.next()).isInstanceOf(SessionManagementFilter.class);
-		assertThat(filters.next()).isInstanceOf(ExceptionTranslationFilter.class);
-		assertThat(filters.next()).isInstanceOf(FilterSecurityInterceptor.class)
-				.hasFieldOrPropertyWithValue("observeOncePerRequest", true);
-	}
-
-	private  T getFilter(Class filterClass) {
-		return (T) getFilters("/").stream().filter(filterClass::isInstance).findFirst().orElse(null);
-	}
-
-	private List getFilters(String url) {
-		FilterChainProxy proxy = this.spring.getContext().getBean(FilterChainProxy.class);
-		return proxy.getFilters(url);
-	}
-
-	private static String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/MultiHttpBlockConfigTests.java b/config/src/test/java/org/springframework/security/config/http/MultiHttpBlockConfigTests.java
index d3e8929d0d..267c810076 100644
--- a/config/src/test/java/org/springframework/security/config/http/MultiHttpBlockConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/MultiHttpBlockConfigTests.java
@@ -88,6 +88,10 @@ public class MultiHttpBlockConfigTests {
 				.andExpect(redirectedUrl("/"));
 	}
 
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@Controller
 	static class BasicController {
 
@@ -98,8 +102,4 @@ public class MultiHttpBlockConfigTests {
 
 	}
 
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParserTests.java
index 46f04f410f..5d9be3a411 100644
--- a/config/src/test/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParserTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParserTests.java
@@ -209,17 +209,6 @@ public class OAuth2ClientBeanDefinitionParserTests {
 		this.mvc.perform(get("/authorized-client")).andExpect(status().isOk()).andExpect(content().string("resolved"));
 	}
 
-	@RestController
-	static class AuthorizedClientController {
-
-		@GetMapping("/authorized-client")
-		String authorizedClient(Model model,
-				@RegisteredOAuth2AuthorizedClient("google") OAuth2AuthorizedClient authorizedClient) {
-			return authorizedClient != null ? "resolved" : "not-resolved";
-		}
-
-	}
-
 	private static OAuth2AuthorizationRequest createAuthorizationRequest(ClientRegistration clientRegistration) {
 		Map attributes = new HashMap<>();
 		attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
@@ -233,4 +222,15 @@ public class OAuth2ClientBeanDefinitionParserTests {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
 
+	@RestController
+	static class AuthorizedClientController {
+
+		@GetMapping("/authorized-client")
+		String authorizedClient(Model model,
+				@RegisteredOAuth2AuthorizedClient("google") OAuth2AuthorizedClient authorizedClient) {
+			return authorizedClient != null ? "resolved" : "not-resolved";
+		}
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java
index 5d29fc8360..6f5608d751 100644
--- a/config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java
@@ -512,6 +512,10 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		this.mvc.perform(get("/authorized-client")).andExpect(status().isOk()).andExpect(content().string("resolved"));
 	}
 
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@RestController
 	static class AuthorizedClientController {
 
@@ -523,8 +527,4 @@ public class OAuth2LoginBeanDefinitionParserTests {
 
 	}
 
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java
index 2617e5405e..66e957d0a7 100644
--- a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java
@@ -892,6 +892,82 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
 		verify(pc.getReaderContext()).error(anyString(), eq(element));
 	}
 
+	private static ResultMatcher invalidRequestHeader(String message) {
+		return header().string(HttpHeaders.WWW_AUTHENTICATE,
+				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_request\", " + "error_description=\""),
+						new StringContains(message),
+						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
+	}
+
+	private static ResultMatcher invalidTokenHeader(String message) {
+		return header().string(HttpHeaders.WWW_AUTHENTICATE,
+				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_token\", " + "error_description=\""),
+						new StringContains(message),
+						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
+	}
+
+	private static ResultMatcher insufficientScopeHeader() {
+		return header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer " + "error=\"insufficient_scope\""
+				+ ", error_description=\"The request requires higher privileges than provided by the access token.\""
+				+ ", error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
+	}
+
+	private String jwkSet() {
+		return new JWKSet(new RSAKey.Builder(TestKeys.DEFAULT_PUBLIC_KEY).keyID("1").build()).toString();
+	}
+
+	private String jwtFromIssuer(String issuer) throws Exception {
+		Map claims = new HashMap<>();
+		claims.put(ISS, issuer);
+		claims.put(SUB, "test-subject");
+		claims.put("scope", "message:read");
+		JWSObject jws = new JWSObject(new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("1").build(),
+				new Payload(new JSONObject(claims)));
+		jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
+		return jws.serialize();
+	}
+
+	private void mockWebServer(String response) {
+		this.web.enqueue(new MockResponse().setResponseCode(200)
+				.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(response));
+	}
+
+	private void mockRestOperations(String response) {
+		RestOperations rest = this.spring.getContext().getBean(RestOperations.class);
+		HttpHeaders headers = new HttpHeaders();
+		headers.setContentType(MediaType.APPLICATION_JSON);
+		ResponseEntity entity = new ResponseEntity<>(response, headers, HttpStatus.OK);
+		Mockito.when(rest.exchange(any(RequestEntity.class), eq(String.class))).thenReturn(entity);
+	}
+
+	private String json(String name) throws IOException {
+		return resource(name + ".json");
+	}
+
+	private String jwks(String name) throws IOException {
+		return resource(name + ".jwks");
+	}
+
+	private String token(String name) throws IOException {
+		return resource(name + ".token");
+	}
+
+	private String resource(String suffix) throws IOException {
+		String name = this.getClass().getSimpleName() + "-" + suffix;
+		ClassPathResource resource = new ClassPathResource(name, this.getClass());
+		try (BufferedReader reader = new BufferedReader(new FileReader(resource.getFile()))) {
+			return reader.lines().collect(Collectors.joining());
+		}
+	}
+
+	private  T bean(Class beanClass) {
+		return this.spring.getContext().getBean(beanClass);
+	}
+
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	static class JwtDecoderFactoryBean implements FactoryBean {
 
 		private RestOperations rest;
@@ -1025,80 +1101,4 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
 
 	}
 
-	private static ResultMatcher invalidRequestHeader(String message) {
-		return header().string(HttpHeaders.WWW_AUTHENTICATE,
-				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_request\", " + "error_description=\""),
-						new StringContains(message),
-						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
-	}
-
-	private static ResultMatcher invalidTokenHeader(String message) {
-		return header().string(HttpHeaders.WWW_AUTHENTICATE,
-				AllOf.allOf(new StringStartsWith("Bearer " + "error=\"invalid_token\", " + "error_description=\""),
-						new StringContains(message),
-						new StringEndsWith(", " + "error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"")));
-	}
-
-	private static ResultMatcher insufficientScopeHeader() {
-		return header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer " + "error=\"insufficient_scope\""
-				+ ", error_description=\"The request requires higher privileges than provided by the access token.\""
-				+ ", error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
-	}
-
-	private String jwkSet() {
-		return new JWKSet(new RSAKey.Builder(TestKeys.DEFAULT_PUBLIC_KEY).keyID("1").build()).toString();
-	}
-
-	private String jwtFromIssuer(String issuer) throws Exception {
-		Map claims = new HashMap<>();
-		claims.put(ISS, issuer);
-		claims.put(SUB, "test-subject");
-		claims.put("scope", "message:read");
-		JWSObject jws = new JWSObject(new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("1").build(),
-				new Payload(new JSONObject(claims)));
-		jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
-		return jws.serialize();
-	}
-
-	private void mockWebServer(String response) {
-		this.web.enqueue(new MockResponse().setResponseCode(200)
-				.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody(response));
-	}
-
-	private void mockRestOperations(String response) {
-		RestOperations rest = this.spring.getContext().getBean(RestOperations.class);
-		HttpHeaders headers = new HttpHeaders();
-		headers.setContentType(MediaType.APPLICATION_JSON);
-		ResponseEntity entity = new ResponseEntity<>(response, headers, HttpStatus.OK);
-		Mockito.when(rest.exchange(any(RequestEntity.class), eq(String.class))).thenReturn(entity);
-	}
-
-	private String json(String name) throws IOException {
-		return resource(name + ".json");
-	}
-
-	private String jwks(String name) throws IOException {
-		return resource(name + ".jwks");
-	}
-
-	private String token(String name) throws IOException {
-		return resource(name + ".token");
-	}
-
-	private String resource(String suffix) throws IOException {
-		String name = this.getClass().getSimpleName() + "-" + suffix;
-		ClassPathResource resource = new ClassPathResource(name, this.getClass());
-		try (BufferedReader reader = new BufferedReader(new FileReader(resource.getFile()))) {
-			return reader.lines().collect(Collectors.joining());
-		}
-	}
-
-	private  T bean(Class beanClass) {
-		return this.spring.getContext().getBean(beanClass);
-	}
-
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/OpenIDConfigTests.java b/config/src/test/java/org/springframework/security/config/http/OpenIDConfigTests.java
index f3021d088a..886be53bb5 100644
--- a/config/src/test/java/org/springframework/security/config/http/OpenIDConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/OpenIDConfigTests.java
@@ -176,16 +176,6 @@ public class OpenIDConfigTests {
 		this.mvc.perform(get("/login")).andExpect(status().isOk()).andExpect(content().string("a custom login page"));
 	}
 
-	@RestController
-	static class CustomLoginController {
-
-		@GetMapping("/login")
-		public String custom() {
-			return "a custom login page";
-		}
-
-	}
-
 	private  T getFilter(Class clazz) {
 		FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
 		return (T) filterChain.getFilters("/").stream().filter(clazz::isInstance).findFirst().orElse(null);
@@ -199,4 +189,14 @@ public class OpenIDConfigTests {
 		return (T) FieldUtils.getFieldValue(bean, fieldName);
 	}
 
+	@RestController
+	static class CustomLoginController {
+
+		@GetMapping("/login")
+		public String custom() {
+			return "a custom login page";
+		}
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/PlaceHolderAndELConfigTests.java b/config/src/test/java/org/springframework/security/config/http/PlaceHolderAndELConfigTests.java
index 075b93570c..e78e90f5a4 100644
--- a/config/src/test/java/org/springframework/security/config/http/PlaceHolderAndELConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/PlaceHolderAndELConfigTests.java
@@ -169,6 +169,10 @@ public class PlaceHolderAndELConfigTests {
 		this.mvc.perform(get("/secured")).andExpect(forwardedUrl("/go-away"));
 	}
 
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@RestController
 	static class SimpleController {
 
@@ -184,8 +188,4 @@ public class PlaceHolderAndELConfigTests {
 
 	}
 
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/RememberMeConfigTests.java b/config/src/test/java/org/springframework/security/config/http/RememberMeConfigTests.java
index e8ce6a5904..8f8731f10e 100644
--- a/config/src/test/java/org/springframework/security/config/http/RememberMeConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/RememberMeConfigTests.java
@@ -302,16 +302,6 @@ public class RememberMeConfigTests {
 								+ "remember-me-parameter or remember-me-cookie");
 	}
 
-	@RestController
-	static class BasicController {
-
-		@GetMapping("/authenticated")
-		String ok() {
-			return "ok";
-		}
-
-	}
-
 	private ResultActions rememberAuthentication(String username, String password) throws Exception {
 
 		return this.mvc.perform(login(username, password).param(DEFAULT_PARAMETER, "true").with(csrf()))
@@ -330,4 +320,14 @@ public class RememberMeConfigTests {
 		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
 	}
 
+	@RestController
+	static class BasicController {
+
+		@GetMapping("/authenticated")
+		String ok() {
+			return "ok";
+		}
+
+	}
+
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests.java b/config/src/test/java/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests.java
index 98d431415a..d2f89090fc 100644
--- a/config/src/test/java/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests.java
@@ -206,6 +206,10 @@ public class SecurityContextHolderAwareRequestConfigTests {
 		this.mvc.perform(get("/role")).andExpect(content().string("true"));
 	}
 
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	@RestController
 	public static class ServletAuthenticatedController {
 
@@ -267,8 +271,4 @@ public class SecurityContextHolderAwareRequestConfigTests {
 
 	}
 
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTests.java b/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTests.java
index ded6945508..00445262d6 100644
--- a/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTests.java
@@ -382,6 +382,49 @@ public class SessionManagementConfigTests {
 		})).andExpect(redirectedUrl("/timeoutUrl"));
 	}
 
+	private void sessionRegistryIsValid() {
+		SessionRegistry sessionRegistry = this.spring.getContext().getBean("sessionRegistry", SessionRegistry.class);
+
+		assertThat(sessionRegistry).isNotNull();
+
+		assertThat(this.getFilter(ConcurrentSessionFilter.class)).returns(sessionRegistry,
+				this::extractSessionRegistry);
+		assertThat(this.getFilter(UsernamePasswordAuthenticationFilter.class)).returns(sessionRegistry,
+				this::extractSessionRegistry);
+		// SEC-1143
+		assertThat(this.getFilter(SessionManagementFilter.class)).returns(sessionRegistry,
+				this::extractSessionRegistry);
+	}
+
+	private SessionRegistry extractSessionRegistry(ConcurrentSessionFilter filter) {
+		return getFieldValue(filter, "sessionRegistry");
+	}
+
+	private SessionRegistry extractSessionRegistry(UsernamePasswordAuthenticationFilter filter) {
+		SessionAuthenticationStrategy strategy = getFieldValue(filter, "sessionStrategy");
+		List strategies = getFieldValue(strategy, "delegateStrategies");
+		return getFieldValue(strategies.get(0), "sessionRegistry");
+	}
+
+	private SessionRegistry extractSessionRegistry(SessionManagementFilter filter) {
+		SessionAuthenticationStrategy strategy = getFieldValue(filter, "sessionAuthenticationStrategy");
+		List strategies = getFieldValue(strategy, "delegateStrategies");
+		return getFieldValue(strategies.get(0), "sessionRegistry");
+	}
+
+	private  T getFieldValue(Object target, String fieldName) {
+		try {
+			return (T) FieldUtils.getFieldValue(target, fieldName);
+		}
+		catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	private static SessionResultMatcher session() {
+		return new SessionResultMatcher();
+	}
+
 	/**
 	 * SEC-2680
 	 */
@@ -408,6 +451,46 @@ public class SessionManagementConfigTests {
 		assertThat(lfLogoutHandlers).hasAtLeastOneElementOfType(LogoutSuccessEventPublishingLogoutHandler.class);
 	}
 
+	private static MockHttpServletResponse request(MockHttpServletRequest request, ApplicationContext context)
+			throws IOException, ServletException {
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+
+		FilterChainProxy proxy = context.getBean(FilterChainProxy.class);
+
+		proxy.doFilter(request, new EncodeUrlDenyingHttpServletResponseWrapper(response), (req, resp) -> {
+		});
+
+		return response;
+	}
+
+	private MockHttpSession expiredSession() {
+		MockHttpSession session = new MockHttpSession();
+		SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
+		sessionRegistry.registerNewSession(session.getId(), "user");
+		sessionRegistry.getSessionInformation(session.getId()).expireNow();
+		return session;
+	}
+
+	private  T getFilter(Class filterClass) {
+		return (T) getFilters().stream().filter(filterClass::isInstance).findFirst().orElse(null);
+	}
+
+	private List getFilters() {
+		FilterChainProxy proxy = this.spring.getContext().getBean(FilterChainProxy.class);
+
+		return proxy.getFilters("/");
+	}
+
+	private ServletContext servletContext() {
+		WebApplicationContext context = this.spring.getContext();
+		return context.getServletContext();
+	}
+
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	static class TeapotSessionAuthenticationStrategy implements SessionAuthenticationStrategy {
 
 		@Override
@@ -459,49 +542,6 @@ public class SessionManagementConfigTests {
 
 	}
 
-	private void sessionRegistryIsValid() {
-		SessionRegistry sessionRegistry = this.spring.getContext().getBean("sessionRegistry", SessionRegistry.class);
-
-		assertThat(sessionRegistry).isNotNull();
-
-		assertThat(this.getFilter(ConcurrentSessionFilter.class)).returns(sessionRegistry,
-				this::extractSessionRegistry);
-		assertThat(this.getFilter(UsernamePasswordAuthenticationFilter.class)).returns(sessionRegistry,
-				this::extractSessionRegistry);
-		// SEC-1143
-		assertThat(this.getFilter(SessionManagementFilter.class)).returns(sessionRegistry,
-				this::extractSessionRegistry);
-	}
-
-	private SessionRegistry extractSessionRegistry(ConcurrentSessionFilter filter) {
-		return getFieldValue(filter, "sessionRegistry");
-	}
-
-	private SessionRegistry extractSessionRegistry(UsernamePasswordAuthenticationFilter filter) {
-		SessionAuthenticationStrategy strategy = getFieldValue(filter, "sessionStrategy");
-		List strategies = getFieldValue(strategy, "delegateStrategies");
-		return getFieldValue(strategies.get(0), "sessionRegistry");
-	}
-
-	private SessionRegistry extractSessionRegistry(SessionManagementFilter filter) {
-		SessionAuthenticationStrategy strategy = getFieldValue(filter, "sessionAuthenticationStrategy");
-		List strategies = getFieldValue(strategy, "delegateStrategies");
-		return getFieldValue(strategies.get(0), "sessionRegistry");
-	}
-
-	private  T getFieldValue(Object target, String fieldName) {
-		try {
-			return (T) FieldUtils.getFieldValue(target, fieldName);
-		}
-		catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	private static SessionResultMatcher session() {
-		return new SessionResultMatcher();
-	}
-
 	private static class SessionResultMatcher implements ResultMatcher {
 
 		private String id;
@@ -552,19 +592,6 @@ public class SessionManagementConfigTests {
 
 	}
 
-	private static MockHttpServletResponse request(MockHttpServletRequest request, ApplicationContext context)
-			throws IOException, ServletException {
-
-		MockHttpServletResponse response = new MockHttpServletResponse();
-
-		FilterChainProxy proxy = context.getBean(FilterChainProxy.class);
-
-		proxy.doFilter(request, new EncodeUrlDenyingHttpServletResponseWrapper(response), (req, resp) -> {
-		});
-
-		return response;
-	}
-
 	private static class EncodeUrlDenyingHttpServletResponseWrapper extends HttpServletResponseWrapper {
 
 		EncodeUrlDenyingHttpServletResponseWrapper(HttpServletResponse response) {
@@ -593,31 +620,4 @@ public class SessionManagementConfigTests {
 
 	}
 
-	private MockHttpSession expiredSession() {
-		MockHttpSession session = new MockHttpSession();
-		SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
-		sessionRegistry.registerNewSession(session.getId(), "user");
-		sessionRegistry.getSessionInformation(session.getId()).expireNow();
-		return session;
-	}
-
-	private  T getFilter(Class filterClass) {
-		return (T) getFilters().stream().filter(filterClass::isInstance).findFirst().orElse(null);
-	}
-
-	private List getFilters() {
-		FilterChainProxy proxy = this.spring.getContext().getBean(FilterChainProxy.class);
-
-		return proxy.getFilters("/");
-	}
-
-	private ServletContext servletContext() {
-		WebApplicationContext context = this.spring.getContext();
-		return context.getServletContext();
-	}
-
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTransientAuthenticationTests.java b/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTransientAuthenticationTests.java
index fe909288bc..8c1c2af17a 100644
--- a/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTransientAuthenticationTests.java
+++ b/config/src/test/java/org/springframework/security/config/http/SessionManagementConfigTransientAuthenticationTests.java
@@ -60,6 +60,10 @@ public class SessionManagementConfigTransientAuthenticationTests {
 		assertThat(result.getRequest().getSession(false)).isNotNull();
 	}
 
+	private String xml(String configName) {
+		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
+	}
+
 	static class TransientAuthenticationProvider implements AuthenticationProvider {
 
 		@Override
@@ -93,8 +97,4 @@ public class SessionManagementConfigTransientAuthenticationTests {
 
 	}
 
-	private String xml(String configName) {
-		return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java
index 25ba7efe8d..81a8a3838d 100644
--- a/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java
+++ b/config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java
@@ -391,6 +391,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
 		foo.foo(new SecurityConfig("A"));
 	}
 
+	private void setContext(String context) {
+		this.appContext = new InMemoryXmlApplicationContext(context);
+	}
+
+	private void setContext(String context, ApplicationContext parent) {
+		this.appContext = new InMemoryXmlApplicationContext(context, parent);
+	}
+
 	static class CustomAuthManager implements AuthenticationManager, ApplicationContextAware {
 
 		private String beanName;
@@ -420,14 +428,6 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
 
 	}
 
-	private void setContext(String context) {
-		this.appContext = new InMemoryXmlApplicationContext(context);
-	}
-
-	private void setContext(String context, ApplicationContext parent) {
-		this.appContext = new InMemoryXmlApplicationContext(context, parent);
-	}
-
 	interface Foo {
 
 		void foo(T action);
diff --git a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java
index df1e409ac7..cdda790028 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java
@@ -256,6 +256,12 @@ public class FormLoginTests {
 		verify(formLoginSecContextRepository).save(any(), any());
 	}
 
+	Mono authentication(Authentication authentication) {
+		SecurityContext context = new SecurityContextImpl();
+		context.setAuthentication(authentication);
+		return Mono.just(context);
+	}
+
 	public static class CustomLoginPage {
 
 		private WebDriver driver;
@@ -491,10 +497,4 @@ public class FormLoginTests {
 
 	}
 
-	Mono authentication(Authentication authentication) {
-		SecurityContext context = new SecurityContextImpl();
-		context.setAuthentication(authentication);
-		return Mono.just(context);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java
index 8942fc5b21..ea814e54fc 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java
@@ -114,41 +114,6 @@ public class OAuth2ClientSpecTests {
 		this.client.get().uri("/").exchange().expectStatus().is3xxRedirection();
 	}
 
-	@EnableWebFlux
-	@EnableWebFluxSecurity
-	static class Config {
-
-		@Bean
-		SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
-			// @formatter:off
-			http
-				.oauth2Client();
-			// @formatter:on
-			return http.build();
-		}
-
-		@Bean
-		ReactiveClientRegistrationRepository clientRegistrationRepository() {
-			return mock(ReactiveClientRegistrationRepository.class);
-		}
-
-		@Bean
-		ServerOAuth2AuthorizedClientRepository authorizedClientRepository() {
-			return mock(ServerOAuth2AuthorizedClientRepository.class);
-		}
-
-	}
-
-	@RestController
-	static class AuthorizedClientController {
-
-		@GetMapping("/")
-		String home(@RegisteredOAuth2AuthorizedClient("github") OAuth2AuthorizedClient authorizedClient) {
-			return "home";
-		}
-
-	}
-
 	@Test
 	public void oauth2ClientWhenCustomObjectsThenUsed() {
 		this.spring.register(ClientRegistrationConfig.class, OAuth2ClientCustomConfig.class,
@@ -189,47 +154,6 @@ public class OAuth2ClientSpecTests {
 		verify(requestCache).getRedirectUri(any());
 	}
 
-	@EnableWebFlux
-	@EnableWebFluxSecurity
-	static class ClientRegistrationConfig {
-
-		private ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
-
-		@Bean
-		InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
-			return new InMemoryReactiveClientRegistrationRepository(this.clientRegistration);
-		}
-
-	}
-
-	@Configuration
-	static class OAuth2ClientCustomConfig {
-
-		ReactiveAuthenticationManager manager = mock(ReactiveAuthenticationManager.class);
-
-		ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
-
-		ServerAuthorizationRequestRepository authorizationRequestRepository = mock(
-				ServerAuthorizationRequestRepository.class);
-
-		ServerRequestCache requestCache = mock(ServerRequestCache.class);
-
-		@Bean
-		public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
-			// @formatter:off
-			http
-				.oauth2Client()
-					.authenticationConverter(this.authenticationConverter)
-					.authenticationManager(this.manager)
-					.authorizationRequestRepository(this.authorizationRequestRepository)
-					.and()
-				.requestCache(c -> c.requestCache(this.requestCache));
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
 	@Test
 	public void oauth2ClientWhenCustomObjectsInLambdaThenUsed() {
 		this.spring.register(ClientRegistrationConfig.class, OAuth2ClientInLambdaCustomConfig.class,
@@ -271,6 +195,82 @@ public class OAuth2ClientSpecTests {
 		verify(requestCache).getRedirectUri(any());
 	}
 
+	@EnableWebFlux
+	@EnableWebFluxSecurity
+	static class Config {
+
+		@Bean
+		SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
+			// @formatter:off
+			http
+				.oauth2Client();
+			// @formatter:on
+			return http.build();
+		}
+
+		@Bean
+		ReactiveClientRegistrationRepository clientRegistrationRepository() {
+			return mock(ReactiveClientRegistrationRepository.class);
+		}
+
+		@Bean
+		ServerOAuth2AuthorizedClientRepository authorizedClientRepository() {
+			return mock(ServerOAuth2AuthorizedClientRepository.class);
+		}
+
+	}
+
+	@RestController
+	static class AuthorizedClientController {
+
+		@GetMapping("/")
+		String home(@RegisteredOAuth2AuthorizedClient("github") OAuth2AuthorizedClient authorizedClient) {
+			return "home";
+		}
+
+	}
+
+	@EnableWebFlux
+	@EnableWebFluxSecurity
+	static class ClientRegistrationConfig {
+
+		private ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+
+		@Bean
+		InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
+			return new InMemoryReactiveClientRegistrationRepository(this.clientRegistration);
+		}
+
+	}
+
+	@Configuration
+	static class OAuth2ClientCustomConfig {
+
+		ReactiveAuthenticationManager manager = mock(ReactiveAuthenticationManager.class);
+
+		ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
+
+		ServerAuthorizationRequestRepository authorizationRequestRepository = mock(
+				ServerAuthorizationRequestRepository.class);
+
+		ServerRequestCache requestCache = mock(ServerRequestCache.class);
+
+		@Bean
+		public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
+			// @formatter:off
+			http
+				.oauth2Client()
+					.authenticationConverter(this.authenticationConverter)
+					.authenticationManager(this.manager)
+					.authorizationRequestRepository(this.authorizationRequestRepository)
+					.and()
+				.requestCache(c -> c.requestCache(this.requestCache));
+			// @formatter:on
+			return http.build();
+		}
+
+	}
+
 	@Configuration
 	static class OAuth2ClientInLambdaCustomConfig {
 
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 50bda99f27..2bb5aaee8c 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
@@ -151,16 +151,6 @@ public class OAuth2LoginTests {
 				.assertClientRegistrationByName(OAuth2LoginTests.github.getClientName()).and();
 	}
 
-	@EnableWebFluxSecurity
-	static class OAuth2LoginWithMultipleClientRegistrations {
-
-		@Bean
-		InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
-			return new InMemoryReactiveClientRegistrationRepository(github, google);
-		}
-
-	}
-
 	@Test
 	public void defaultLoginPageWithSingleClientRegistrationThenRedirect() {
 		this.spring.register(OAuth2LoginWithSingleClientRegistrations.class).autowire();
@@ -184,21 +174,6 @@ public class OAuth2LoginTests {
 				.is3xxRedirection().expectHeader().valueEquals(HttpHeaders.LOCATION, "/login");
 	}
 
-	@EnableWebFlux
-	static class WebFluxConfig {
-
-	}
-
-	@EnableWebFluxSecurity
-	static class OAuth2LoginWithSingleClientRegistrations {
-
-		@Bean
-		InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
-			return new InMemoryReactiveClientRegistrationRepository(github);
-		}
-
-	}
-
 	@Test
 	public void oauth2AuthorizeWhenCustomObjectsThenUsed() {
 		this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, OAuth2AuthorizeWithMockObjectsConfig.class,
@@ -223,47 +198,6 @@ public class OAuth2LoginTests {
 		verify(requestCache).saveRequest(any());
 	}
 
-	@EnableWebFlux
-	static class OAuth2AuthorizeWithMockObjectsConfig {
-
-		ServerOAuth2AuthorizedClientRepository authorizedClientRepository = mock(
-				ServerOAuth2AuthorizedClientRepository.class);
-
-		ServerAuthorizationRequestRepository authorizationRequestRepository = mock(
-				ServerAuthorizationRequestRepository.class);
-
-		ServerRequestCache requestCache = mock(ServerRequestCache.class);
-
-		@Bean
-		SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
-			// @formatter:off
-			http
-				.requestCache()
-					.requestCache(this.requestCache)
-					.and()
-				.oauth2Login()
-					.authorizationRequestRepository(this.authorizationRequestRepository);
-			// @formatter:on
-			return http.build();
-		}
-
-		@Bean
-		ServerOAuth2AuthorizedClientRepository authorizedClientRepository() {
-			return this.authorizedClientRepository;
-		}
-
-	}
-
-	@RestController
-	static class AuthorizedClientController {
-
-		@GetMapping("/")
-		String home(@RegisteredOAuth2AuthorizedClient("github") OAuth2AuthorizedClient authorizedClient) {
-			return "home";
-		}
-
-	}
-
 	@Test
 	public void oauth2LoginWhenCustomObjectsThenUsed() {
 		this.spring.register(OAuth2LoginWithSingleClientRegistrations.class,
@@ -359,41 +293,6 @@ public class OAuth2LoginTests {
 		verify(failureHandler).onAuthenticationFailure(any(), any());
 	}
 
-	@Configuration
-	static class OAuth2LoginMockAuthenticationManagerConfig {
-
-		ReactiveAuthenticationManager manager = mock(ReactiveAuthenticationManager.class);
-
-		ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
-
-		ServerWebExchangeMatcher matcher = mock(ServerWebExchangeMatcher.class);
-
-		ServerOAuth2AuthorizationRequestResolver resolver = mock(ServerOAuth2AuthorizationRequestResolver.class);
-
-		ServerAuthenticationSuccessHandler successHandler = mock(ServerAuthenticationSuccessHandler.class);
-
-		ServerAuthenticationFailureHandler failureHandler = mock(ServerAuthenticationFailureHandler.class);
-
-		@Bean
-		public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
-			// @formatter:off
-			http
-				.authorizeExchange()
-					.anyExchange().authenticated()
-					.and()
-				.oauth2Login()
-					.authenticationConverter(this.authenticationConverter)
-					.authenticationManager(this.manager)
-					.authenticationMatcher(this.matcher)
-					.authorizationRequestResolver(this.resolver)
-					.authenticationSuccessHandler(this.successHandler)
-					.authenticationFailureHandler(this.failureHandler);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
 	@Test
 	public void oauth2LoginWhenCustomObjectsInLambdaThenUsed() {
 		this.spring.register(OAuth2LoginWithSingleClientRegistrations.class,
@@ -440,41 +339,6 @@ public class OAuth2LoginTests {
 		verify(successHandler).onAuthenticationSuccess(any(), any());
 	}
 
-	@Configuration
-	static class OAuth2LoginMockAuthenticationManagerInLambdaConfig {
-
-		ReactiveAuthenticationManager manager = mock(ReactiveAuthenticationManager.class);
-
-		ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
-
-		ServerWebExchangeMatcher matcher = mock(ServerWebExchangeMatcher.class);
-
-		ServerOAuth2AuthorizationRequestResolver resolver = mock(ServerOAuth2AuthorizationRequestResolver.class);
-
-		ServerAuthenticationSuccessHandler successHandler = mock(ServerAuthenticationSuccessHandler.class);
-
-		@Bean
-		public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
-			// @formatter:off
-			http
-				.authorizeExchange(exchanges ->
-					exchanges
-						.anyExchange().authenticated()
-				)
-				.oauth2Login(oauth2Login ->
-					oauth2Login
-						.authenticationConverter(this.authenticationConverter)
-						.authenticationManager(this.manager)
-						.authenticationMatcher(this.matcher)
-						.authorizationRequestResolver(this.resolver)
-						.authenticationSuccessHandler(this.successHandler)
-				);
-			// @formatter:on
-			return http.build();
-		}
-
-	}
-
 	@Test
 	public void oauth2LoginWhenCustomBeansThenUsed() {
 		this.spring.register(OAuth2LoginWithMultipleClientRegistrations.class, OAuth2LoginWithCustomBeansConfig.class)
@@ -585,6 +449,177 @@ public class OAuth2LoginTests {
 				.valueEquals("Location", "/login?error");
 	}
 
+	@Test
+	public void logoutWhenUsingOidcLogoutHandlerThenRedirects() {
+		this.spring.register(OAuth2LoginConfigWithOidcLogoutSuccessHandler.class).autowire();
+
+		OAuth2AuthenticationToken token = new OAuth2AuthenticationToken(TestOidcUsers.create(),
+				AuthorityUtils.NO_AUTHORITIES, getBean(ClientRegistration.class).getRegistrationId());
+
+		ServerSecurityContextRepository repository = getBean(ServerSecurityContextRepository.class);
+		when(repository.load(any())).thenReturn(authentication(token));
+
+		this.client.post().uri("/logout").exchange().expectHeader().valueEquals("Location",
+				"https://logout?id_token_hint=id-token");
+	}
+
+	// gh-8609
+	@Test
+	public void oauth2LoginWhenAuthenticationConverterFailsThenDefaultRedirectToLogin() {
+		this.spring.register(OAuth2LoginWithMultipleClientRegistrations.class).autowire();
+
+		WebTestClient webTestClient = WebTestClientBuilder.bindToWebFilters(this.springSecurity).build();
+
+		webTestClient.get().uri("/login/oauth2/code/google").exchange().expectStatus().is3xxRedirection().expectHeader()
+				.valueEquals("Location", "/login?error");
+	}
+
+	Mono authentication(Authentication authentication) {
+		SecurityContext context = new SecurityContextImpl();
+		context.setAuthentication(authentication);
+		return Mono.just(context);
+	}
+
+	 T getBean(Class beanClass) {
+		return this.spring.getContext().getBean(beanClass);
+	}
+
+	@EnableWebFluxSecurity
+	static class OAuth2LoginWithMultipleClientRegistrations {
+
+		@Bean
+		InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
+			return new InMemoryReactiveClientRegistrationRepository(github, google);
+		}
+
+	}
+
+	@EnableWebFlux
+	static class WebFluxConfig {
+
+	}
+
+	@EnableWebFluxSecurity
+	static class OAuth2LoginWithSingleClientRegistrations {
+
+		@Bean
+		InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
+			return new InMemoryReactiveClientRegistrationRepository(github);
+		}
+
+	}
+
+	@EnableWebFlux
+	static class OAuth2AuthorizeWithMockObjectsConfig {
+
+		ServerOAuth2AuthorizedClientRepository authorizedClientRepository = mock(
+				ServerOAuth2AuthorizedClientRepository.class);
+
+		ServerAuthorizationRequestRepository authorizationRequestRepository = mock(
+				ServerAuthorizationRequestRepository.class);
+
+		ServerRequestCache requestCache = mock(ServerRequestCache.class);
+
+		@Bean
+		SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
+			// @formatter:off
+			http
+				.requestCache()
+					.requestCache(this.requestCache)
+					.and()
+				.oauth2Login()
+					.authorizationRequestRepository(this.authorizationRequestRepository);
+			// @formatter:on
+			return http.build();
+		}
+
+		@Bean
+		ServerOAuth2AuthorizedClientRepository authorizedClientRepository() {
+			return this.authorizedClientRepository;
+		}
+
+	}
+
+	@RestController
+	static class AuthorizedClientController {
+
+		@GetMapping("/")
+		String home(@RegisteredOAuth2AuthorizedClient("github") OAuth2AuthorizedClient authorizedClient) {
+			return "home";
+		}
+
+	}
+
+	@Configuration
+	static class OAuth2LoginMockAuthenticationManagerConfig {
+
+		ReactiveAuthenticationManager manager = mock(ReactiveAuthenticationManager.class);
+
+		ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
+
+		ServerWebExchangeMatcher matcher = mock(ServerWebExchangeMatcher.class);
+
+		ServerOAuth2AuthorizationRequestResolver resolver = mock(ServerOAuth2AuthorizationRequestResolver.class);
+
+		ServerAuthenticationSuccessHandler successHandler = mock(ServerAuthenticationSuccessHandler.class);
+
+		ServerAuthenticationFailureHandler failureHandler = mock(ServerAuthenticationFailureHandler.class);
+
+		@Bean
+		public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
+			// @formatter:off
+			http
+				.authorizeExchange()
+					.anyExchange().authenticated()
+					.and()
+				.oauth2Login()
+					.authenticationConverter(this.authenticationConverter)
+					.authenticationManager(this.manager)
+					.authenticationMatcher(this.matcher)
+					.authorizationRequestResolver(this.resolver)
+					.authenticationSuccessHandler(this.successHandler)
+					.authenticationFailureHandler(this.failureHandler);
+			// @formatter:on
+			return http.build();
+		}
+
+	}
+
+	@Configuration
+	static class OAuth2LoginMockAuthenticationManagerInLambdaConfig {
+
+		ReactiveAuthenticationManager manager = mock(ReactiveAuthenticationManager.class);
+
+		ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
+
+		ServerWebExchangeMatcher matcher = mock(ServerWebExchangeMatcher.class);
+
+		ServerOAuth2AuthorizationRequestResolver resolver = mock(ServerOAuth2AuthorizationRequestResolver.class);
+
+		ServerAuthenticationSuccessHandler successHandler = mock(ServerAuthenticationSuccessHandler.class);
+
+		@Bean
+		public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
+			// @formatter:off
+			http
+				.authorizeExchange(exchanges ->
+					exchanges
+						.anyExchange().authenticated()
+				)
+				.oauth2Login(oauth2Login ->
+					oauth2Login
+						.authenticationConverter(this.authenticationConverter)
+						.authenticationManager(this.manager)
+						.authenticationMatcher(this.matcher)
+						.authorizationRequestResolver(this.resolver)
+						.authenticationSuccessHandler(this.successHandler)
+				);
+			// @formatter:on
+			return http.build();
+		}
+
+	}
+
 	@Configuration
 	static class OAuth2LoginWithCustomBeansConfig {
 
@@ -654,20 +689,6 @@ public class OAuth2LoginTests {
 
 	}
 
-	@Test
-	public void logoutWhenUsingOidcLogoutHandlerThenRedirects() {
-		this.spring.register(OAuth2LoginConfigWithOidcLogoutSuccessHandler.class).autowire();
-
-		OAuth2AuthenticationToken token = new OAuth2AuthenticationToken(TestOidcUsers.create(),
-				AuthorityUtils.NO_AUTHORITIES, getBean(ClientRegistration.class).getRegistrationId());
-
-		ServerSecurityContextRepository repository = getBean(ServerSecurityContextRepository.class);
-		when(repository.load(any())).thenReturn(authentication(token));
-
-		this.client.post().uri("/logout").exchange().expectHeader().valueEquals("Location",
-				"https://logout?id_token_hint=id-token");
-	}
-
 	@EnableWebFlux
 	@EnableWebFluxSecurity
 	static class OAuth2LoginConfigWithOidcLogoutSuccessHandler {
@@ -707,17 +728,6 @@ public class OAuth2LoginTests {
 
 	}
 
-	// gh-8609
-	@Test
-	public void oauth2LoginWhenAuthenticationConverterFailsThenDefaultRedirectToLogin() {
-		this.spring.register(OAuth2LoginWithMultipleClientRegistrations.class).autowire();
-
-		WebTestClient webTestClient = WebTestClientBuilder.bindToWebFilters(this.springSecurity).build();
-
-		webTestClient.get().uri("/login/oauth2/code/google").exchange().expectStatus().is3xxRedirection().expectHeader()
-				.valueEquals("Location", "/login?error");
-	}
-
 	static class GitHubWebFilter implements WebFilter {
 
 		@Override
@@ -730,14 +740,4 @@ public class OAuth2LoginTests {
 
 	}
 
-	Mono authentication(Authentication authentication) {
-		SecurityContext context = new SecurityContextImpl();
-		context.setAuthentication(authentication);
-		return Mono.just(context);
-	}
-
-	 T getBean(Class beanClass) {
-		return this.spring.getContext().getBean(beanClass);
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java
index 8026f28f4d..5d4962a5fa 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java
@@ -412,6 +412,54 @@ public class OAuth2ResourceServerSpecTests {
 				.isInstanceOf(BeanCreationException.class).hasMessageContaining("authenticationManagerResolver");
 	}
 
+	private static Dispatcher requiresAuth(String username, String password, String response) {
+		return new Dispatcher() {
+			@Override
+			public MockResponse dispatch(RecordedRequest request) {
+				String authorization = request.getHeader(org.springframework.http.HttpHeaders.AUTHORIZATION);
+				return Optional.ofNullable(authorization).filter(a -> isAuthorized(authorization, username, password))
+						.map(a -> ok(response)).orElse(unauthorized());
+			}
+		};
+	}
+
+	private static boolean isAuthorized(String authorization, String username, String password) {
+		String[] values = new String(Base64.getDecoder().decode(authorization.substring(6))).split(":");
+		return username.equals(values[0]) && password.equals(values[1]);
+	}
+
+	private static MockResponse ok(String response) {
+		return new MockResponse().setBody(response).setHeader(org.springframework.http.HttpHeaders.CONTENT_TYPE,
+				MediaType.APPLICATION_JSON_VALUE);
+	}
+
+	private static MockResponse unauthorized() {
+		return new MockResponse().setResponseCode(401);
+	}
+
+	private static RSAPublicKey publicKey() {
+		String modulus = "26323220897278656456354815752829448539647589990395639665273015355787577386000316054335559633864476469390247312823732994485311378484154955583861993455004584140858982659817218753831620205191028763754231454775026027780771426040997832758235764611119743390612035457533732596799927628476322029280486807310749948064176545712270582940917249337311592011920620009965129181413510845780806191965771671528886508636605814099711121026468495328702234901200169245493126030184941412539949521815665744267183140084667383643755535107759061065656273783542590997725982989978433493861515415520051342321336460543070448417126615154138673620797";
+		String exponent = "65537";
+
+		RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
+		RSAPublicKey rsaPublicKey = null;
+		try {
+			KeyFactory factory = KeyFactory.getInstance("RSA");
+			rsaPublicKey = (RSAPublicKey) factory.generatePublic(spec);
+		}
+		catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+			e.printStackTrace();
+		}
+		return rsaPublicKey;
+	}
+
+	private GenericWebApplicationContext autowireWebServerGenericWebApplicationContext() {
+		GenericWebApplicationContext context = new GenericWebApplicationContext();
+		context.registerBean("webHandler", DispatcherHandler.class);
+		this.spring.context(context).autowire();
+		return (GenericWebApplicationContext) this.spring.getContext();
+	}
+
 	@EnableWebFlux
 	@EnableWebFluxSecurity
 	static class PublicKeyConfig {
@@ -865,52 +913,4 @@ public class OAuth2ResourceServerSpecTests {
 
 	}
 
-	private static Dispatcher requiresAuth(String username, String password, String response) {
-		return new Dispatcher() {
-			@Override
-			public MockResponse dispatch(RecordedRequest request) {
-				String authorization = request.getHeader(org.springframework.http.HttpHeaders.AUTHORIZATION);
-				return Optional.ofNullable(authorization).filter(a -> isAuthorized(authorization, username, password))
-						.map(a -> ok(response)).orElse(unauthorized());
-			}
-		};
-	}
-
-	private static boolean isAuthorized(String authorization, String username, String password) {
-		String[] values = new String(Base64.getDecoder().decode(authorization.substring(6))).split(":");
-		return username.equals(values[0]) && password.equals(values[1]);
-	}
-
-	private static MockResponse ok(String response) {
-		return new MockResponse().setBody(response).setHeader(org.springframework.http.HttpHeaders.CONTENT_TYPE,
-				MediaType.APPLICATION_JSON_VALUE);
-	}
-
-	private static MockResponse unauthorized() {
-		return new MockResponse().setResponseCode(401);
-	}
-
-	private static RSAPublicKey publicKey() {
-		String modulus = "26323220897278656456354815752829448539647589990395639665273015355787577386000316054335559633864476469390247312823732994485311378484154955583861993455004584140858982659817218753831620205191028763754231454775026027780771426040997832758235764611119743390612035457533732596799927628476322029280486807310749948064176545712270582940917249337311592011920620009965129181413510845780806191965771671528886508636605814099711121026468495328702234901200169245493126030184941412539949521815665744267183140084667383643755535107759061065656273783542590997725982989978433493861515415520051342321336460543070448417126615154138673620797";
-		String exponent = "65537";
-
-		RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
-		RSAPublicKey rsaPublicKey = null;
-		try {
-			KeyFactory factory = KeyFactory.getInstance("RSA");
-			rsaPublicKey = (RSAPublicKey) factory.generatePublic(spec);
-		}
-		catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-			e.printStackTrace();
-		}
-		return rsaPublicKey;
-	}
-
-	private GenericWebApplicationContext autowireWebServerGenericWebApplicationContext() {
-		GenericWebApplicationContext context = new GenericWebApplicationContext();
-		context.registerBean("webHandler", DispatcherHandler.class);
-		this.spring.context(context).autowire();
-		return (GenericWebApplicationContext) this.spring.getContext();
-	}
-
 }
diff --git a/config/src/test/java/org/springframework/security/htmlunit/server/WebTestClientHtmlUnitDriverBuilderTests.java b/config/src/test/java/org/springframework/security/htmlunit/server/WebTestClientHtmlUnitDriverBuilderTests.java
index c1e4aa01d9..c1c02565db 100644
--- a/config/src/test/java/org/springframework/security/htmlunit/server/WebTestClientHtmlUnitDriverBuilderTests.java
+++ b/config/src/test/java/org/springframework/security/htmlunit/server/WebTestClientHtmlUnitDriverBuilderTests.java
@@ -52,22 +52,6 @@ public class WebTestClientHtmlUnitDriverBuilderTests {
 		assertThat(driver.getPageSource()).contains("Hello World");
 	}
 
-	/**
-	 * @author Rob Winch
-	 * @since 5.0
-	 */
-	@Controller
-	class HelloWorldController {
-
-		@ResponseBody
-		@GetMapping(produces = MediaType.TEXT_HTML_VALUE)
-		public String index() {
-			return "\n" + "\n" + "Hello World\n" + "\n" + "\n"
-					+ "

Hello World

\n" + "\n" + ""; - } - - } - @Test public void cookies() { WebTestClient webTestClient = WebTestClient.bindToController(new CookieController()).build(); @@ -82,6 +66,18 @@ public class WebTestClientHtmlUnitDriverBuilderTests { assertThat(driver.getPageSource()).contains("null"); } + @Controller + class HelloWorldController { + + @ResponseBody + @GetMapping(produces = MediaType.TEXT_HTML_VALUE) + public String index() { + return "\n" + "\n" + "Hello World\n" + "\n" + "\n" + + "

Hello World

\n" + "\n" + ""; + } + + } + @Controller @ResponseBody class CookieController { diff --git a/core/src/main/java/org/springframework/security/core/userdetails/User.java b/core/src/main/java/org/springframework/security/core/userdetails/User.java index 12bf83f72a..e3c8fe469e 100644 --- a/core/src/main/java/org/springframework/security/core/userdetails/User.java +++ b/core/src/main/java/org/springframework/security/core/userdetails/User.java @@ -175,29 +175,6 @@ public class User implements UserDetails, CredentialsContainer { return sortedAuthorities; } - private static class AuthorityComparator implements Comparator, Serializable { - - private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; - - @Override - public int compare(GrantedAuthority g1, GrantedAuthority g2) { - // Neither should ever be null as each entry is checked before adding it to - // the set. - // If the authority is null, it is a custom authority and should precede - // others. - if (g2.getAuthority() == null) { - return -1; - } - - if (g1.getAuthority() == null) { - return 1; - } - - return g1.getAuthority().compareTo(g2.getAuthority()); - } - - } - /** * Returns {@code true} if the supplied object is a {@code User} instance with the * same {@code username} value. @@ -339,6 +316,29 @@ public class User implements UserDetails, CredentialsContainer { .disabled(!userDetails.isEnabled()); } + private static class AuthorityComparator implements Comparator, Serializable { + + private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; + + @Override + public int compare(GrantedAuthority g1, GrantedAuthority g2) { + // Neither should ever be null as each entry is checked before adding it to + // the set. + // If the authority is null, it is a custom authority and should precede + // others. + if (g2.getAuthority() == null) { + return -1; + } + + if (g1.getAuthority() == null) { + return 1; + } + + return g1.getAuthority().compareTo(g2.getAuthority()); + } + + } + /** * Builds the user to be added. At minimum the username, password, and authorities * should provided. The remaining attributes have reasonable defaults. diff --git a/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java b/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java index 46fe362801..b3993f2f5d 100644 --- a/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java +++ b/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java @@ -683,6 +683,12 @@ public class DaoAuthenticationProviderTests { verify(encoder, times(0)).matches(anyString(), anyString()); } + private DaoAuthenticationProvider createProvider() { + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setPasswordEncoder(NoOpPasswordEncoder.getInstance()); + return provider; + } + private class MockUserDetailsServiceReturnsNull implements UserDetailsService { @Override @@ -767,10 +773,4 @@ public class DaoAuthenticationProviderTests { } - private DaoAuthenticationProvider createProvider() { - DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); - provider.setPasswordEncoder(NoOpPasswordEncoder.getInstance()); - return provider; - } - } diff --git a/etc/checkstyle/checkstyle-suppressions.xml b/etc/checkstyle/checkstyle-suppressions.xml index 839b07e350..07b0071dd4 100644 --- a/etc/checkstyle/checkstyle-suppressions.xml +++ b/etc/checkstyle/checkstyle-suppressions.xml @@ -3,7 +3,6 @@ "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" "https://checkstyle.org/dtds/suppressions_1_2.dtd"> - diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java index a5fb47cd56..ef8c2b440f 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java @@ -58,6 +58,46 @@ public class UnboundIdContainerLdifTests { assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue(); } + @Test + public void unboundIdContainerWhenWildcardLdifNameThenLdifLoaded() { + this.appCtx = new AnnotationConfigApplicationContext(WildcardLdifConfig.class); + + DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) this.appCtx + .getBean(ContextSource.class); + + SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource); + assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue(); + } + + @Test + public void unboundIdContainerWhenMalformedLdifThenException() { + try { + this.appCtx = new AnnotationConfigApplicationContext(MalformedLdifConfig.class); + failBecauseExceptionWasNotThrown(IllegalStateException.class); + } + catch (Exception e) { + assertThat(e.getCause()).isInstanceOf(IllegalStateException.class); + assertThat(e.getMessage()).contains("Unable to load LDIF classpath:test-server-malformed.txt"); + } + } + + @Test + public void unboundIdContainerWhenMissingLdifThenException() { + try { + this.appCtx = new AnnotationConfigApplicationContext(MissingLdifConfig.class); + failBecauseExceptionWasNotThrown(IllegalStateException.class); + } + catch (Exception e) { + assertThat(e.getCause()).isInstanceOf(IllegalStateException.class); + assertThat(e.getMessage()).contains("Unable to load LDIF classpath:does-not-exist.ldif"); + } + } + + @Test + public void unboundIdContainerWhenWildcardLdifNotFoundThenProceeds() { + new AnnotationConfigApplicationContext(WildcardNoLdifConfig.class); + } + @Configuration static class CustomLdifConfig { @@ -83,17 +123,6 @@ public class UnboundIdContainerLdifTests { } - @Test - public void unboundIdContainerWhenWildcardLdifNameThenLdifLoaded() { - this.appCtx = new AnnotationConfigApplicationContext(WildcardLdifConfig.class); - - DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) this.appCtx - .getBean(ContextSource.class); - - SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource); - assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue(); - } - @Configuration static class WildcardLdifConfig { @@ -119,18 +148,6 @@ public class UnboundIdContainerLdifTests { } - @Test - public void unboundIdContainerWhenMalformedLdifThenException() { - try { - this.appCtx = new AnnotationConfigApplicationContext(MalformedLdifConfig.class); - failBecauseExceptionWasNotThrown(IllegalStateException.class); - } - catch (Exception e) { - assertThat(e.getCause()).isInstanceOf(IllegalStateException.class); - assertThat(e.getMessage()).contains("Unable to load LDIF classpath:test-server-malformed.txt"); - } - } - @Configuration static class MalformedLdifConfig { @@ -150,18 +167,6 @@ public class UnboundIdContainerLdifTests { } - @Test - public void unboundIdContainerWhenMissingLdifThenException() { - try { - this.appCtx = new AnnotationConfigApplicationContext(MissingLdifConfig.class); - failBecauseExceptionWasNotThrown(IllegalStateException.class); - } - catch (Exception e) { - assertThat(e.getCause()).isInstanceOf(IllegalStateException.class); - assertThat(e.getMessage()).contains("Unable to load LDIF classpath:does-not-exist.ldif"); - } - } - @Configuration static class MissingLdifConfig { @@ -181,11 +186,6 @@ public class UnboundIdContainerLdifTests { } - @Test - public void unboundIdContainerWhenWildcardLdifNotFoundThenProceeds() { - new AnnotationConfigApplicationContext(WildcardNoLdifConfig.class); - } - @Configuration static class WildcardNoLdifConfig { diff --git a/messaging/src/test/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolverTests.java b/messaging/src/test/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolverTests.java index a483b5a870..4bcd5168ec 100644 --- a/messaging/src/test/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolverTests.java +++ b/messaging/src/test/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolverTests.java @@ -200,6 +200,12 @@ public class AuthenticationPrincipalArgumentResolverTests { return new MethodParameter(method, 0); } + private void setAuthenticationPrincipal(Object principal) { + this.expectedPrincipal = principal; + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken(this.expectedPrincipal, "password", "ROLE_USER")); + } + @Target({ ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @AuthenticationPrincipal @@ -301,10 +307,4 @@ public class AuthenticationPrincipalArgumentResolverTests { } - private void setAuthenticationPrincipal(Object principal) { - this.expectedPrincipal = principal; - SecurityContextHolder.getContext() - .setAuthentication(new TestingAuthenticationToken(this.expectedPrincipal, "password", "ROLE_USER")); - } - } diff --git a/messaging/src/test/java/org/springframework/security/messaging/handler/invocation/ResolvableMethod.java b/messaging/src/test/java/org/springframework/security/messaging/handler/invocation/ResolvableMethod.java index 78e0e1fcbd..25e1e6af82 100644 --- a/messaging/src/test/java/org/springframework/security/messaging/handler/invocation/ResolvableMethod.java +++ b/messaging/src/test/java/org/springframework/security/messaging/handler/invocation/ResolvableMethod.java @@ -255,6 +255,52 @@ public final class ResolvableMethod { return new Builder<>(objectClass); } + @SuppressWarnings("unchecked") + private static T initProxy(Class type, MethodInvocationInterceptor interceptor) { + Assert.notNull(type, "'type' must not be null"); + if (type.isInterface()) { + ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE); + factory.addInterface(type); + factory.addInterface(Supplier.class); + factory.addAdvice(interceptor); + return (T) factory.getProxy(); + } + + else { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(type); + enhancer.setInterfaces(new Class[] { Supplier.class }); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); + enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); + + Class proxyClass = enhancer.createClass(); + Object proxy = null; + + if (objenesis.isWorthTrying()) { + try { + proxy = objenesis.newInstance(proxyClass, enhancer.getUseCache()); + } + catch (ObjenesisException ex) { + logger.debug("Objenesis failed, falling back to default constructor", ex); + } + } + + if (proxy == null) { + try { + proxy = ReflectionUtils.accessibleConstructor(proxyClass).newInstance(); + } + catch (Throwable ex) { + throw new IllegalStateException( + "Unable to instantiate proxy " + "via both Objenesis and default constructor fails as well", + ex); + } + } + + ((Factory) proxy).setCallbacks(new Callback[] { interceptor }); + return (T) proxy; + } + } + /** * Builder for {@code ResolvableMethod}. */ @@ -629,50 +675,4 @@ public final class ResolvableMethod { } - @SuppressWarnings("unchecked") - private static T initProxy(Class type, MethodInvocationInterceptor interceptor) { - Assert.notNull(type, "'type' must not be null"); - if (type.isInterface()) { - ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE); - factory.addInterface(type); - factory.addInterface(Supplier.class); - factory.addAdvice(interceptor); - return (T) factory.getProxy(); - } - - else { - Enhancer enhancer = new Enhancer(); - enhancer.setSuperclass(type); - enhancer.setInterfaces(new Class[] { Supplier.class }); - enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); - enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); - - Class proxyClass = enhancer.createClass(); - Object proxy = null; - - if (objenesis.isWorthTrying()) { - try { - proxy = objenesis.newInstance(proxyClass, enhancer.getUseCache()); - } - catch (ObjenesisException ex) { - logger.debug("Objenesis failed, falling back to default constructor", ex); - } - } - - if (proxy == null) { - try { - proxy = ReflectionUtils.accessibleConstructor(proxyClass).newInstance(); - } - catch (Throwable ex) { - throw new IllegalStateException( - "Unable to instantiate proxy " + "via both Objenesis and default constructor fails as well", - ex); - } - } - - ((Factory) proxy).setCallbacks(new Callback[] { interceptor }); - return (T) proxy; - } - } - } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java index 4a510258e8..a0541d8eb7 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java @@ -86,25 +86,6 @@ public final class OAuth2AuthorizedClientProviderBuilder { return OAuth2AuthorizedClientProviderBuilder.this; } - /** - * A builder for the {@code authorization_code} grant. - */ - public final class AuthorizationCodeGrantBuilder implements Builder { - - private AuthorizationCodeGrantBuilder() { - } - - /** - * Builds an instance of {@link AuthorizationCodeOAuth2AuthorizedClientProvider}. - * @return the {@link AuthorizationCodeOAuth2AuthorizedClientProvider} - */ - @Override - public OAuth2AuthorizedClientProvider build() { - return new AuthorizationCodeOAuth2AuthorizedClientProvider(); - } - - } - /** * Configures support for the {@code refresh_token} grant. * @return the {@link OAuth2AuthorizedClientProviderBuilder} @@ -128,77 +109,6 @@ public final class OAuth2AuthorizedClientProviderBuilder { return OAuth2AuthorizedClientProviderBuilder.this; } - /** - * A builder for the {@code refresh_token} grant. - */ - public final class RefreshTokenGrantBuilder implements Builder { - - private OAuth2AccessTokenResponseClient accessTokenResponseClient; - - private Duration clockSkew; - - private Clock clock; - - private RefreshTokenGrantBuilder() { - } - - /** - * Sets the client used when requesting an access token credential at the Token - * Endpoint. - * @param accessTokenResponseClient the client used when requesting an access - * token credential at the Token Endpoint - * @return the {@link RefreshTokenGrantBuilder} - */ - public RefreshTokenGrantBuilder accessTokenResponseClient( - OAuth2AccessTokenResponseClient accessTokenResponseClient) { - this.accessTokenResponseClient = accessTokenResponseClient; - return this; - } - - /** - * Sets the maximum acceptable clock skew, which is used when checking the access - * token expiry. An access token is considered expired if it's before - * {@code Instant.now(this.clock) - clockSkew}. - * @param clockSkew the maximum acceptable clock skew - * @return the {@link RefreshTokenGrantBuilder} - */ - public RefreshTokenGrantBuilder clockSkew(Duration clockSkew) { - this.clockSkew = clockSkew; - return this; - } - - /** - * Sets the {@link Clock} used in {@link Instant#now(Clock)} when checking the - * access token expiry. - * @param clock the clock - * @return the {@link RefreshTokenGrantBuilder} - */ - public RefreshTokenGrantBuilder clock(Clock clock) { - this.clock = clock; - return this; - } - - /** - * Builds an instance of {@link RefreshTokenOAuth2AuthorizedClientProvider}. - * @return the {@link RefreshTokenOAuth2AuthorizedClientProvider} - */ - @Override - public OAuth2AuthorizedClientProvider build() { - RefreshTokenOAuth2AuthorizedClientProvider authorizedClientProvider = new RefreshTokenOAuth2AuthorizedClientProvider(); - if (this.accessTokenResponseClient != null) { - authorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient); - } - if (this.clockSkew != null) { - authorizedClientProvider.setClockSkew(this.clockSkew); - } - if (this.clock != null) { - authorizedClientProvider.setClock(this.clock); - } - return authorizedClientProvider; - } - - } - /** * Configures support for the {@code client_credentials} grant. * @return the {@link OAuth2AuthorizedClientProviderBuilder} @@ -223,77 +133,6 @@ public final class OAuth2AuthorizedClientProviderBuilder { return OAuth2AuthorizedClientProviderBuilder.this; } - /** - * A builder for the {@code client_credentials} grant. - */ - public final class ClientCredentialsGrantBuilder implements Builder { - - private OAuth2AccessTokenResponseClient accessTokenResponseClient; - - private Duration clockSkew; - - private Clock clock; - - private ClientCredentialsGrantBuilder() { - } - - /** - * Sets the client used when requesting an access token credential at the Token - * Endpoint. - * @param accessTokenResponseClient the client used when requesting an access - * token credential at the Token Endpoint - * @return the {@link ClientCredentialsGrantBuilder} - */ - public ClientCredentialsGrantBuilder accessTokenResponseClient( - OAuth2AccessTokenResponseClient accessTokenResponseClient) { - this.accessTokenResponseClient = accessTokenResponseClient; - return this; - } - - /** - * Sets the maximum acceptable clock skew, which is used when checking the access - * token expiry. An access token is considered expired if it's before - * {@code Instant.now(this.clock) - clockSkew}. - * @param clockSkew the maximum acceptable clock skew - * @return the {@link ClientCredentialsGrantBuilder} - */ - public ClientCredentialsGrantBuilder clockSkew(Duration clockSkew) { - this.clockSkew = clockSkew; - return this; - } - - /** - * Sets the {@link Clock} used in {@link Instant#now(Clock)} when checking the - * access token expiry. - * @param clock the clock - * @return the {@link ClientCredentialsGrantBuilder} - */ - public ClientCredentialsGrantBuilder clock(Clock clock) { - this.clock = clock; - return this; - } - - /** - * Builds an instance of {@link ClientCredentialsOAuth2AuthorizedClientProvider}. - * @return the {@link ClientCredentialsOAuth2AuthorizedClientProvider} - */ - @Override - public OAuth2AuthorizedClientProvider build() { - ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider = new ClientCredentialsOAuth2AuthorizedClientProvider(); - if (this.accessTokenResponseClient != null) { - authorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient); - } - if (this.clockSkew != null) { - authorizedClientProvider.setClockSkew(this.clockSkew); - } - if (this.clock != null) { - authorizedClientProvider.setClock(this.clock); - } - return authorizedClientProvider; - } - - } - /** * Configures support for the {@code password} grant. * @return the {@link OAuth2AuthorizedClientProviderBuilder} @@ -316,6 +155,25 @@ public final class OAuth2AuthorizedClientProviderBuilder { return OAuth2AuthorizedClientProviderBuilder.this; } + /** + * Builds an instance of {@link DelegatingOAuth2AuthorizedClientProvider} composed of + * one or more {@link OAuth2AuthorizedClientProvider}(s). + * @return the {@link DelegatingOAuth2AuthorizedClientProvider} + */ + public OAuth2AuthorizedClientProvider build() { + List authorizedClientProviders = new ArrayList<>(); + for (Builder builder : this.builders.values()) { + authorizedClientProviders.add(builder.build()); + } + return new DelegatingOAuth2AuthorizedClientProvider(authorizedClientProviders); + } + + interface Builder { + + OAuth2AuthorizedClientProvider build(); + + } + /** * A builder for the {@code password} grant. */ @@ -388,21 +246,163 @@ public final class OAuth2AuthorizedClientProviderBuilder { } /** - * Builds an instance of {@link DelegatingOAuth2AuthorizedClientProvider} composed of - * one or more {@link OAuth2AuthorizedClientProvider}(s). - * @return the {@link DelegatingOAuth2AuthorizedClientProvider} + * A builder for the {@code client_credentials} grant. */ - public OAuth2AuthorizedClientProvider build() { - List authorizedClientProviders = new ArrayList<>(); - for (Builder builder : this.builders.values()) { - authorizedClientProviders.add(builder.build()); + public final class ClientCredentialsGrantBuilder implements Builder { + + private OAuth2AccessTokenResponseClient accessTokenResponseClient; + + private Duration clockSkew; + + private Clock clock; + + private ClientCredentialsGrantBuilder() { } - return new DelegatingOAuth2AuthorizedClientProvider(authorizedClientProviders); + + /** + * Sets the client used when requesting an access token credential at the Token + * Endpoint. + * @param accessTokenResponseClient the client used when requesting an access + * token credential at the Token Endpoint + * @return the {@link ClientCredentialsGrantBuilder} + */ + public ClientCredentialsGrantBuilder accessTokenResponseClient( + OAuth2AccessTokenResponseClient accessTokenResponseClient) { + this.accessTokenResponseClient = accessTokenResponseClient; + return this; + } + + /** + * Sets the maximum acceptable clock skew, which is used when checking the access + * token expiry. An access token is considered expired if it's before + * {@code Instant.now(this.clock) - clockSkew}. + * @param clockSkew the maximum acceptable clock skew + * @return the {@link ClientCredentialsGrantBuilder} + */ + public ClientCredentialsGrantBuilder clockSkew(Duration clockSkew) { + this.clockSkew = clockSkew; + return this; + } + + /** + * Sets the {@link Clock} used in {@link Instant#now(Clock)} when checking the + * access token expiry. + * @param clock the clock + * @return the {@link ClientCredentialsGrantBuilder} + */ + public ClientCredentialsGrantBuilder clock(Clock clock) { + this.clock = clock; + return this; + } + + /** + * Builds an instance of {@link ClientCredentialsOAuth2AuthorizedClientProvider}. + * @return the {@link ClientCredentialsOAuth2AuthorizedClientProvider} + */ + @Override + public OAuth2AuthorizedClientProvider build() { + ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider = new ClientCredentialsOAuth2AuthorizedClientProvider(); + if (this.accessTokenResponseClient != null) { + authorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient); + } + if (this.clockSkew != null) { + authorizedClientProvider.setClockSkew(this.clockSkew); + } + if (this.clock != null) { + authorizedClientProvider.setClock(this.clock); + } + return authorizedClientProvider; + } + } - interface Builder { + /** + * A builder for the {@code authorization_code} grant. + */ + public final class AuthorizationCodeGrantBuilder implements Builder { - OAuth2AuthorizedClientProvider build(); + private AuthorizationCodeGrantBuilder() { + } + + /** + * Builds an instance of {@link AuthorizationCodeOAuth2AuthorizedClientProvider}. + * @return the {@link AuthorizationCodeOAuth2AuthorizedClientProvider} + */ + @Override + public OAuth2AuthorizedClientProvider build() { + return new AuthorizationCodeOAuth2AuthorizedClientProvider(); + } + + } + + /** + * A builder for the {@code refresh_token} grant. + */ + public final class RefreshTokenGrantBuilder implements Builder { + + private OAuth2AccessTokenResponseClient accessTokenResponseClient; + + private Duration clockSkew; + + private Clock clock; + + private RefreshTokenGrantBuilder() { + } + + /** + * Sets the client used when requesting an access token credential at the Token + * Endpoint. + * @param accessTokenResponseClient the client used when requesting an access + * token credential at the Token Endpoint + * @return the {@link RefreshTokenGrantBuilder} + */ + public RefreshTokenGrantBuilder accessTokenResponseClient( + OAuth2AccessTokenResponseClient accessTokenResponseClient) { + this.accessTokenResponseClient = accessTokenResponseClient; + return this; + } + + /** + * Sets the maximum acceptable clock skew, which is used when checking the access + * token expiry. An access token is considered expired if it's before + * {@code Instant.now(this.clock) - clockSkew}. + * @param clockSkew the maximum acceptable clock skew + * @return the {@link RefreshTokenGrantBuilder} + */ + public RefreshTokenGrantBuilder clockSkew(Duration clockSkew) { + this.clockSkew = clockSkew; + return this; + } + + /** + * Sets the {@link Clock} used in {@link Instant#now(Clock)} when checking the + * access token expiry. + * @param clock the clock + * @return the {@link RefreshTokenGrantBuilder} + */ + public RefreshTokenGrantBuilder clock(Clock clock) { + this.clock = clock; + return this; + } + + /** + * Builds an instance of {@link RefreshTokenOAuth2AuthorizedClientProvider}. + * @return the {@link RefreshTokenOAuth2AuthorizedClientProvider} + */ + @Override + public OAuth2AuthorizedClientProvider build() { + RefreshTokenOAuth2AuthorizedClientProvider authorizedClientProvider = new RefreshTokenOAuth2AuthorizedClientProvider(); + if (this.accessTokenResponseClient != null) { + authorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient); + } + if (this.clockSkew != null) { + authorizedClientProvider.setClockSkew(this.clockSkew); + } + if (this.clock != null) { + authorizedClientProvider.setClock(this.clock); + } + return authorizedClientProvider; + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java index 2e6eb85eb4..c817be8527 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java @@ -86,26 +86,6 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { return ReactiveOAuth2AuthorizedClientProviderBuilder.this; } - /** - * A builder for the {@code authorization_code} grant. - */ - public final class AuthorizationCodeGrantBuilder implements Builder { - - private AuthorizationCodeGrantBuilder() { - } - - /** - * Builds an instance of - * {@link AuthorizationCodeReactiveOAuth2AuthorizedClientProvider}. - * @return the {@link AuthorizationCodeReactiveOAuth2AuthorizedClientProvider} - */ - @Override - public ReactiveOAuth2AuthorizedClientProvider build() { - return new AuthorizationCodeReactiveOAuth2AuthorizedClientProvider(); - } - - } - /** * Configures support for the {@code refresh_token} grant. * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} @@ -130,78 +110,6 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { return ReactiveOAuth2AuthorizedClientProviderBuilder.this; } - /** - * A builder for the {@code refresh_token} grant. - */ - public final class RefreshTokenGrantBuilder implements Builder { - - private ReactiveOAuth2AccessTokenResponseClient accessTokenResponseClient; - - private Duration clockSkew; - - private Clock clock; - - private RefreshTokenGrantBuilder() { - } - - /** - * Sets the client used when requesting an access token credential at the Token - * Endpoint. - * @param accessTokenResponseClient the client used when requesting an access - * token credential at the Token Endpoint - * @return the {@link RefreshTokenGrantBuilder} - */ - public RefreshTokenGrantBuilder accessTokenResponseClient( - ReactiveOAuth2AccessTokenResponseClient accessTokenResponseClient) { - this.accessTokenResponseClient = accessTokenResponseClient; - return this; - } - - /** - * Sets the maximum acceptable clock skew, which is used when checking the access - * token expiry. An access token is considered expired if it's before - * {@code Instant.now(this.clock) - clockSkew}. - * @param clockSkew the maximum acceptable clock skew - * @return the {@link RefreshTokenGrantBuilder} - */ - public RefreshTokenGrantBuilder clockSkew(Duration clockSkew) { - this.clockSkew = clockSkew; - return this; - } - - /** - * Sets the {@link Clock} used in {@link Instant#now(Clock)} when checking the - * access token expiry. - * @param clock the clock - * @return the {@link RefreshTokenGrantBuilder} - */ - public RefreshTokenGrantBuilder clock(Clock clock) { - this.clock = clock; - return this; - } - - /** - * Builds an instance of - * {@link RefreshTokenReactiveOAuth2AuthorizedClientProvider}. - * @return the {@link RefreshTokenReactiveOAuth2AuthorizedClientProvider} - */ - @Override - public ReactiveOAuth2AuthorizedClientProvider build() { - RefreshTokenReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = new RefreshTokenReactiveOAuth2AuthorizedClientProvider(); - if (this.accessTokenResponseClient != null) { - authorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient); - } - if (this.clockSkew != null) { - authorizedClientProvider.setClockSkew(this.clockSkew); - } - if (this.clock != null) { - authorizedClientProvider.setClock(this.clock); - } - return authorizedClientProvider; - } - - } - /** * Configures support for the {@code client_credentials} grant. * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} @@ -227,6 +135,66 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { return ReactiveOAuth2AuthorizedClientProviderBuilder.this; } + /** + * Configures support for the {@code password} grant. + * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} + */ + public ReactiveOAuth2AuthorizedClientProviderBuilder password() { + this.builders.computeIfAbsent(PasswordReactiveOAuth2AuthorizedClientProvider.class, + k -> new PasswordGrantBuilder()); + return ReactiveOAuth2AuthorizedClientProviderBuilder.this; + } + + /** + * Configures support for the {@code password} grant. + * @param builderConsumer a {@code Consumer} of {@link PasswordGrantBuilder} used for + * further configuration + * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} + */ + public ReactiveOAuth2AuthorizedClientProviderBuilder password(Consumer builderConsumer) { + PasswordGrantBuilder builder = (PasswordGrantBuilder) this.builders + .computeIfAbsent(PasswordReactiveOAuth2AuthorizedClientProvider.class, k -> new PasswordGrantBuilder()); + builderConsumer.accept(builder); + return ReactiveOAuth2AuthorizedClientProviderBuilder.this; + } + + /** + * Builds an instance of {@link DelegatingReactiveOAuth2AuthorizedClientProvider} + * composed of one or more {@link ReactiveOAuth2AuthorizedClientProvider}(s). + * @return the {@link DelegatingReactiveOAuth2AuthorizedClientProvider} + */ + public ReactiveOAuth2AuthorizedClientProvider build() { + List authorizedClientProviders = this.builders.values().stream() + .map(Builder::build).collect(Collectors.toList()); + return new DelegatingReactiveOAuth2AuthorizedClientProvider(authorizedClientProviders); + } + + interface Builder { + + ReactiveOAuth2AuthorizedClientProvider build(); + + } + + /** + * A builder for the {@code authorization_code} grant. + */ + public final class AuthorizationCodeGrantBuilder implements Builder { + + private AuthorizationCodeGrantBuilder() { + } + + /** + * Builds an instance of + * {@link AuthorizationCodeReactiveOAuth2AuthorizedClientProvider}. + * @return the {@link AuthorizationCodeReactiveOAuth2AuthorizedClientProvider} + */ + @Override + public ReactiveOAuth2AuthorizedClientProvider build() { + return new AuthorizationCodeReactiveOAuth2AuthorizedClientProvider(); + } + + } + /** * A builder for the {@code client_credentials} grant. */ @@ -299,29 +267,6 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { } - /** - * Configures support for the {@code password} grant. - * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} - */ - public ReactiveOAuth2AuthorizedClientProviderBuilder password() { - this.builders.computeIfAbsent(PasswordReactiveOAuth2AuthorizedClientProvider.class, - k -> new PasswordGrantBuilder()); - return ReactiveOAuth2AuthorizedClientProviderBuilder.this; - } - - /** - * Configures support for the {@code password} grant. - * @param builderConsumer a {@code Consumer} of {@link PasswordGrantBuilder} used for - * further configuration - * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} - */ - public ReactiveOAuth2AuthorizedClientProviderBuilder password(Consumer builderConsumer) { - PasswordGrantBuilder builder = (PasswordGrantBuilder) this.builders - .computeIfAbsent(PasswordReactiveOAuth2AuthorizedClientProvider.class, k -> new PasswordGrantBuilder()); - builderConsumer.accept(builder); - return ReactiveOAuth2AuthorizedClientProviderBuilder.this; - } - /** * A builder for the {@code password} grant. */ @@ -394,19 +339,74 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { } /** - * Builds an instance of {@link DelegatingReactiveOAuth2AuthorizedClientProvider} - * composed of one or more {@link ReactiveOAuth2AuthorizedClientProvider}(s). - * @return the {@link DelegatingReactiveOAuth2AuthorizedClientProvider} + * A builder for the {@code refresh_token} grant. */ - public ReactiveOAuth2AuthorizedClientProvider build() { - List authorizedClientProviders = this.builders.values().stream() - .map(Builder::build).collect(Collectors.toList()); - return new DelegatingReactiveOAuth2AuthorizedClientProvider(authorizedClientProviders); - } + public final class RefreshTokenGrantBuilder implements Builder { - interface Builder { + private ReactiveOAuth2AccessTokenResponseClient accessTokenResponseClient; - ReactiveOAuth2AuthorizedClientProvider build(); + private Duration clockSkew; + + private Clock clock; + + private RefreshTokenGrantBuilder() { + } + + /** + * Sets the client used when requesting an access token credential at the Token + * Endpoint. + * @param accessTokenResponseClient the client used when requesting an access + * token credential at the Token Endpoint + * @return the {@link RefreshTokenGrantBuilder} + */ + public RefreshTokenGrantBuilder accessTokenResponseClient( + ReactiveOAuth2AccessTokenResponseClient accessTokenResponseClient) { + this.accessTokenResponseClient = accessTokenResponseClient; + return this; + } + + /** + * Sets the maximum acceptable clock skew, which is used when checking the access + * token expiry. An access token is considered expired if it's before + * {@code Instant.now(this.clock) - clockSkew}. + * @param clockSkew the maximum acceptable clock skew + * @return the {@link RefreshTokenGrantBuilder} + */ + public RefreshTokenGrantBuilder clockSkew(Duration clockSkew) { + this.clockSkew = clockSkew; + return this; + } + + /** + * Sets the {@link Clock} used in {@link Instant#now(Clock)} when checking the + * access token expiry. + * @param clock the clock + * @return the {@link RefreshTokenGrantBuilder} + */ + public RefreshTokenGrantBuilder clock(Clock clock) { + this.clock = clock; + return this; + } + + /** + * Builds an instance of + * {@link RefreshTokenReactiveOAuth2AuthorizedClientProvider}. + * @return the {@link RefreshTokenReactiveOAuth2AuthorizedClientProvider} + */ + @Override + public ReactiveOAuth2AuthorizedClientProvider build() { + RefreshTokenReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = new RefreshTokenReactiveOAuth2AuthorizedClientProvider(); + if (this.accessTokenResponseClient != null) { + authorizedClientProvider.setAccessTokenResponseClient(this.accessTokenResponseClient); + } + if (this.clockSkew != null) { + authorizedClientProvider.setClockSkew(this.clockSkew); + } + if (this.clock != null) { + authorizedClientProvider.setClock(this.clock); + } + return authorizedClientProvider; + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java index 51df5fb0c7..79a4007f70 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientOAuth2AuthorizationFailureHandler.java @@ -81,29 +81,6 @@ public class RemoveAuthorizedClientOAuth2AuthorizationFailureHandler implements */ private final OAuth2AuthorizedClientRemover delegate; - /** - * Removes an {@link OAuth2AuthorizedClient} from an - * {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}. - */ - @FunctionalInterface - public interface OAuth2AuthorizedClientRemover { - - /** - * Removes the {@link OAuth2AuthorizedClient} associated to the provided client - * registration identifier and End-User {@link Authentication} (Resource Owner). - * @param clientRegistrationId the identifier for the client's registration - * @param principal the End-User {@link Authentication} (Resource Owner) - * @param attributes an immutable {@code Map} of (optional) attributes present - * under certain conditions. For example, this might contain a - * {@code javax.servlet.http.HttpServletRequest} and - * {@code javax.servlet.http.HttpServletResponse} if the authorization was - * performed within the context of a {@code javax.servlet.ServletContext}. - */ - void removeAuthorizedClient(String clientRegistrationId, Authentication principal, - Map attributes); - - } - /** * Constructs a {@code RemoveAuthorizedClientOAuth2AuthorizationFailureHandler} using * the provided parameters. @@ -159,4 +136,27 @@ public class RemoveAuthorizedClientOAuth2AuthorizationFailureHandler implements return this.removeAuthorizedClientErrorCodes.contains(authorizationException.getError().getErrorCode()); } + /** + * Removes an {@link OAuth2AuthorizedClient} from an + * {@link OAuth2AuthorizedClientRepository} or {@link OAuth2AuthorizedClientService}. + */ + @FunctionalInterface + public interface OAuth2AuthorizedClientRemover { + + /** + * Removes the {@link OAuth2AuthorizedClient} associated to the provided client + * registration identifier and End-User {@link Authentication} (Resource Owner). + * @param clientRegistrationId the identifier for the client's registration + * @param principal the End-User {@link Authentication} (Resource Owner) + * @param attributes an immutable {@code Map} of (optional) attributes present + * under certain conditions. For example, this might contain a + * {@code javax.servlet.http.HttpServletRequest} and + * {@code javax.servlet.http.HttpServletResponse} if the authorization was + * performed within the context of a {@code javax.servlet.ServletContext}. + */ + void removeAuthorizedClient(String clientRegistrationId, Authentication principal, + Map attributes); + + } + } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java index 179ce268ec..0e52150bdb 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler.java @@ -79,32 +79,6 @@ public class RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler */ private final Set removeAuthorizedClientErrorCodes; - /** - * Removes an {@link OAuth2AuthorizedClient} from a - * {@link ServerOAuth2AuthorizedClientRepository} or - * {@link ReactiveOAuth2AuthorizedClientService}. - */ - @FunctionalInterface - public interface OAuth2AuthorizedClientRemover { - - /** - * Removes the {@link OAuth2AuthorizedClient} associated to the provided client - * registration identifier and End-User {@link Authentication} (Resource Owner). - * @param clientRegistrationId the identifier for the client's registration - * @param principal the End-User {@link Authentication} (Resource Owner) - * @param attributes an immutable {@code Map} of extra optional attributes present - * under certain conditions. For example, this might contain a - * {@link org.springframework.web.server.ServerWebExchange ServerWebExchange} if - * the authorization was performed within the context of a - * {@code ServerWebExchange}. - * @return an empty {@link Mono} that completes after this handler has finished - * handling the event. - */ - Mono removeAuthorizedClient(String clientRegistrationId, Authentication principal, - Map attributes); - - } - /** * Constructs a * {@code RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler} using the @@ -165,4 +139,30 @@ public class RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler return this.removeAuthorizedClientErrorCodes.contains(authorizationException.getError().getErrorCode()); } + /** + * Removes an {@link OAuth2AuthorizedClient} from a + * {@link ServerOAuth2AuthorizedClientRepository} or + * {@link ReactiveOAuth2AuthorizedClientService}. + */ + @FunctionalInterface + public interface OAuth2AuthorizedClientRemover { + + /** + * Removes the {@link OAuth2AuthorizedClient} associated to the provided client + * registration identifier and End-User {@link Authentication} (Resource Owner). + * @param clientRegistrationId the identifier for the client's registration + * @param principal the End-User {@link Authentication} (Resource Owner) + * @param attributes an immutable {@code Map} of extra optional attributes present + * under certain conditions. For example, this might contain a + * {@link org.springframework.web.server.ServerWebExchange ServerWebExchange} if + * the authorization was performed within the context of a + * {@code ServerWebExchange}. + * @return an empty {@link Mono} that completes after this handler has finished + * handling the event. + */ + Mono removeAuthorizedClient(String clientRegistrationId, Authentication principal, + Map attributes); + + } + } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java index b4ecb5748d..12050c253a 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java @@ -176,6 +176,28 @@ public final class ClientRegistration implements Serializable { + this.providerDetails + ", clientName='" + this.clientName + '\'' + '}'; } + /** + * Returns a new {@link Builder}, initialized with the provided registration + * identifier. + * @param registrationId the identifier for the registration + * @return the {@link Builder} + */ + public static Builder withRegistrationId(String registrationId) { + Assert.hasText(registrationId, "registrationId cannot be empty"); + return new Builder(registrationId); + } + + /** + * Returns a new {@link Builder}, initialized with the provided + * {@link ClientRegistration}. + * @param clientRegistration the {@link ClientRegistration} to copy from + * @return the {@link Builder} + */ + public static Builder withClientRegistration(ClientRegistration clientRegistration) { + Assert.notNull(clientRegistration, "clientRegistration cannot be null"); + return new Builder(clientRegistration); + } + /** * Details of the Provider. */ @@ -297,28 +319,6 @@ public final class ClientRegistration implements Serializable { } - /** - * Returns a new {@link Builder}, initialized with the provided registration - * identifier. - * @param registrationId the identifier for the registration - * @return the {@link Builder} - */ - public static Builder withRegistrationId(String registrationId) { - Assert.hasText(registrationId, "registrationId cannot be empty"); - return new Builder(registrationId); - } - - /** - * Returns a new {@link Builder}, initialized with the provided - * {@link ClientRegistration}. - * @param clientRegistration the {@link ClientRegistration} to copy from - * @return the {@link Builder} - */ - public static Builder withClientRegistration(ClientRegistration clientRegistration) { - Assert.notNull(clientRegistration, "clientRegistration cannot be null"); - return new Builder(clientRegistration); - } - /** * A builder for {@link ClientRegistration}. */ diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java index aa68f450c1..e244de0e8d 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java @@ -64,6 +64,9 @@ public final class ClientRegistrations { private static final ParameterizedTypeReference> typeReference = new ParameterizedTypeReference>() { }; + private ClientRegistrations() { + } + /** * Creates a {@link ClientRegistration.Builder} using the provided Issuer @@ -227,12 +230,6 @@ public final class ClientRegistrations { } } - private interface ThrowingFunction { - - T apply(S src) throws E; - - } - private static ClientRegistration.Builder withProviderConfiguration(AuthorizationServerMetadata metadata, String issuer) { String metadataIssuer = metadata.getIssuer().getValue(); @@ -292,7 +289,10 @@ public final class ClientRegistrations { } } - private ClientRegistrations() { + private interface ThrowingFunction { + + T apply(S src) throws E; + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java index 9ea3263d5b..d8b0dfea79 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java @@ -154,13 +154,6 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements private ClientResponseHandler clientResponseHandler; - @FunctionalInterface - private interface ClientResponseHandler { - - Mono handleResponse(ClientRequest request, Mono response); - - } - /** * Constructs a {@code ServerOAuth2AuthorizedClientExchangeFilterFunction} using the * provided parameters. @@ -534,6 +527,13 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements this.clientResponseHandler = new AuthorizationFailureForwarder(authorizationFailureHandler); } + @FunctionalInterface + private interface ClientResponseHandler { + + Mono handleResponse(ClientRequest request, Mono response); + + } + private static final class UnAuthenticatedReactiveOAuth2AuthorizedClientManager implements ReactiveOAuth2AuthorizedClientManager { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java index 6600151027..311e403766 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java @@ -166,13 +166,6 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement private ClientResponseHandler clientResponseHandler; - @FunctionalInterface - private interface ClientResponseHandler { - - Mono handleResponse(ClientRequest request, Mono response); - - } - public ServletOAuth2AuthorizedClientExchangeFilterFunction() { } @@ -631,6 +624,13 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement }; } + @FunctionalInterface + private interface ClientResponseHandler { + + Mono handleResponse(ClientRequest request, Mono response); + + } + /** * Forwards authentication and authorization failures to an * {@link OAuth2AuthorizationFailureHandler}. diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java index 53a119cdb0..4fa7bac01a 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java @@ -245,6 +245,19 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { return new JwkSourceReactiveJwtDecoderBuilder(source); } + private static JWTClaimsSet createClaimsSet(JWTProcessor jwtProcessor, + JWT parsedToken, C context) { + try { + return jwtProcessor.process(parsedToken, context); + } + catch (BadJOSEException e) { + throw new BadJwtException("Failed to validate the token", e); + } + catch (JOSEException e) { + throw new JwtException("Failed to validate the token", e); + } + } + /** * A builder for creating {@link NimbusReactiveJwtDecoder} instances based on a * JWK Set @@ -626,17 +639,4 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { } - private static JWTClaimsSet createClaimsSet(JWTProcessor jwtProcessor, - JWT parsedToken, C context) { - try { - return jwtProcessor.process(parsedToken, context); - } - catch (BadJOSEException e) { - throw new BadJwtException("Failed to validate the token", e); - } - catch (JOSEException e) { - throw new JwtException("Failed to validate the token", e); - } - } - } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java index cf749a5361..842f58df26 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java @@ -562,6 +562,22 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi return xsAny.getTextContent(); } + private static Saml2Error validationError(String code, String description) { + return new Saml2Error(code, description); + } + + private static Saml2AuthenticationException authException(String code, String description) + throws Saml2AuthenticationException { + + return new Saml2AuthenticationException(validationError(code, description)); + } + + private static Saml2AuthenticationException authException(String code, String description, Exception cause) + throws Saml2AuthenticationException { + + return new Saml2AuthenticationException(validationError(code, description), cause); + } + private static class SignatureTrustEngineConverter implements Converter { @@ -651,22 +667,6 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi } - private static Saml2Error validationError(String code, String description) { - return new Saml2Error(code, description); - } - - private static Saml2AuthenticationException authException(String code, String description) - throws Saml2AuthenticationException { - - return new Saml2AuthenticationException(validationError(code, description)); - } - - private static Saml2AuthenticationException authException(String code, String description, Exception cause) - throws Saml2AuthenticationException { - - return new Saml2AuthenticationException(validationError(code, description), cause); - } - /** * A tuple containing the authentication token and the associated OpenSAML * {@link Response}. diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java index 7a5db9ed5d..db1f7d2d57 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java @@ -377,6 +377,51 @@ public final class RelyingPartyRegistration { registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())); } + private static Saml2X509Credential fromDeprecated( + org.springframework.security.saml2.credentials.Saml2X509Credential credential) { + PrivateKey privateKey = credential.getPrivateKey(); + X509Certificate certificate = credential.getCertificate(); + Set credentialTypes = new HashSet<>(); + if (credential.isSigningCredential()) { + credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.SIGNING); + } + if (credential.isSignatureVerficationCredential()) { + credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.VERIFICATION); + } + if (credential.isEncryptionCredential()) { + credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION); + } + if (credential.isDecryptionCredential()) { + credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.DECRYPTION); + } + return new Saml2X509Credential(privateKey, certificate, credentialTypes); + } + + private static org.springframework.security.saml2.credentials.Saml2X509Credential toDeprecated( + Saml2X509Credential credential) { + PrivateKey privateKey = credential.getPrivateKey(); + X509Certificate certificate = credential.getCertificate(); + Set credentialTypes = new HashSet<>(); + if (credential.isSigningCredential()) { + credentialTypes.add( + org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING); + } + if (credential.isVerificationCredential()) { + credentialTypes.add( + org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION); + } + if (credential.isEncryptionCredential()) { + credentialTypes.add( + org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION); + } + if (credential.isDecryptionCredential()) { + credentialTypes.add( + org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION); + } + return new org.springframework.security.saml2.credentials.Saml2X509Credential(privateKey, certificate, + credentialTypes); + } + /** * The configuration metadata of the Asserting party * @@ -1000,49 +1045,4 @@ public final class RelyingPartyRegistration { } - private static Saml2X509Credential fromDeprecated( - org.springframework.security.saml2.credentials.Saml2X509Credential credential) { - PrivateKey privateKey = credential.getPrivateKey(); - X509Certificate certificate = credential.getCertificate(); - Set credentialTypes = new HashSet<>(); - if (credential.isSigningCredential()) { - credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.SIGNING); - } - if (credential.isSignatureVerficationCredential()) { - credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.VERIFICATION); - } - if (credential.isEncryptionCredential()) { - credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION); - } - if (credential.isDecryptionCredential()) { - credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.DECRYPTION); - } - return new Saml2X509Credential(privateKey, certificate, credentialTypes); - } - - private static org.springframework.security.saml2.credentials.Saml2X509Credential toDeprecated( - Saml2X509Credential credential) { - PrivateKey privateKey = credential.getPrivateKey(); - X509Certificate certificate = credential.getCertificate(); - Set credentialTypes = new HashSet<>(); - if (credential.isSigningCredential()) { - credentialTypes.add( - org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING); - } - if (credential.isVerificationCredential()) { - credentialTypes.add( - org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION); - } - if (credential.isEncryptionCredential()) { - credentialTypes.add( - org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION); - } - if (credential.isDecryptionCredential()) { - credentialTypes.add( - org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION); - } - return new org.springframework.security.saml2.credentials.Saml2X509Credential(privateKey, certificate, - credentialTypes); - } - } diff --git a/test/src/main/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListener.java b/test/src/main/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListener.java index 3c14d2ce20..97572bdf8e 100644 --- a/test/src/main/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListener.java +++ b/test/src/main/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListener.java @@ -57,6 +57,14 @@ public class ReactorContextTestExecutionListener extends DelegatingTestExecution }; } + /** + * Returns {@code 11000}. + */ + @Override + public int getOrder() { + return 11000; + } + private static class DelegateTestExecutionListener extends AbstractTestExecutionListener { @Override @@ -124,12 +132,4 @@ public class ReactorContextTestExecutionListener extends DelegatingTestExecution } - /** - * Returns {@code 11000}. - */ - @Override - public int getOrder() { - return 11000; - } - } diff --git a/test/src/test/java/org/springframework/security/test/context/showcase/WithUserDetailsTests.java b/test/src/test/java/org/springframework/security/test/context/showcase/WithUserDetailsTests.java index 29cbaebbc5..604dcbfbf9 100644 --- a/test/src/test/java/org/springframework/security/test/context/showcase/WithUserDetailsTests.java +++ b/test/src/test/java/org/springframework/security/test/context/showcase/WithUserDetailsTests.java @@ -76,6 +76,10 @@ public class WithUserDetailsTests { assertThat(getPrincipal()).isInstanceOf(CustomUserDetails.class); } + private Object getPrincipal() { + return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + @EnableGlobalMethodSecurity(prePostEnabled = true) @ComponentScan(basePackageClasses = HelloMessageService.class) static class Config { @@ -95,10 +99,6 @@ public class WithUserDetailsTests { } - private Object getPrincipal() { - return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - } - static class CustomUserDetailsService implements UserDetailsService { @Override diff --git a/test/src/test/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListenerTests.java b/test/src/test/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListenerTests.java index 82aa46912e..915f0997fc 100644 --- a/test/src/test/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListenerTests.java +++ b/test/src/test/java/org/springframework/security/test/context/support/ReactorContextTestExecutionListenerTests.java @@ -100,26 +100,6 @@ public class ReactorContextTestExecutionListenerTests { assertSecurityContext(context); } - static class CustomContext implements SecurityContext { - - private Authentication authentication; - - CustomContext(Authentication authentication) { - this.authentication = authentication; - } - - @Override - public Authentication getAuthentication() { - return this.authentication; - } - - @Override - public void setAuthentication(Authentication authentication) { - this.authentication = authentication; - } - - } - @Test public void beforeTestMethodWhenExistingAuthenticationThenReactorContextHasOriginalAuthentication() throws Exception { @@ -215,4 +195,24 @@ public class ReactorContextTestExecutionListenerTests { StepVerifier.create(securityContext).expectNext(expected).verifyComplete(); } + static class CustomContext implements SecurityContext { + + private Authentication authentication; + + CustomContext(Authentication authentication) { + this.authentication = authentication; + } + + @Override + public Authentication getAuthentication() { + return this.authentication; + } + + @Override + public void setAuthentication(Authentication authentication) { + this.authentication = authentication; + } + + } + } diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithAnonymousUserTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithAnonymousUserTests.java index 7922953309..451d0be461 100644 --- a/test/src/test/java/org/springframework/security/test/context/support/WithAnonymousUserTests.java +++ b/test/src/test/java/org/springframework/security/test/context/support/WithAnonymousUserTests.java @@ -36,11 +36,6 @@ public class WithAnonymousUserTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_METHOD); } - @WithAnonymousUser - private class Annotated { - - } - @Test public void findMergedAnnotationWhenSetupExplicitThenOverridden() { WithSecurityContext context = AnnotatedElementUtils.findMergedAnnotation(SetupExplicit.class, @@ -49,11 +44,6 @@ public class WithAnonymousUserTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_METHOD); } - @WithAnonymousUser(setupBefore = TestExecutionEvent.TEST_METHOD) - private class SetupExplicit { - - } - @Test public void findMergedAnnotationWhenSetupOverriddenThenOverridden() { WithSecurityContext context = AnnotatedElementUtils.findMergedAnnotation(SetupOverridden.class, @@ -62,6 +52,16 @@ public class WithAnonymousUserTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_EXECUTION); } + @WithAnonymousUser + private class Annotated { + + } + + @WithAnonymousUser(setupBefore = TestExecutionEvent.TEST_METHOD) + private class SetupExplicit { + + } + @WithAnonymousUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) private class SetupOverridden { diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java index 50f1cf76ab..b64c85ef7a 100644 --- a/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java +++ b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java @@ -39,11 +39,6 @@ public class WithMockUserTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_METHOD); } - @WithMockUser - private class Annotated { - - } - @Test public void findMergedAnnotationWhenSetupExplicitThenOverridden() { WithSecurityContext context = AnnotatedElementUtils.findMergedAnnotation(SetupExplicit.class, @@ -52,11 +47,6 @@ public class WithMockUserTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_METHOD); } - @WithMockUser(setupBefore = TestExecutionEvent.TEST_METHOD) - private class SetupExplicit { - - } - @Test public void findMergedAnnotationWhenSetupOverriddenThenOverridden() { WithSecurityContext context = AnnotatedElementUtils.findMergedAnnotation(SetupOverridden.class, @@ -65,6 +55,16 @@ public class WithMockUserTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_EXECUTION); } + @WithMockUser + private class Annotated { + + } + + @WithMockUser(setupBefore = TestExecutionEvent.TEST_METHOD) + private class SetupExplicit { + + } + @WithMockUser(setupBefore = TestExecutionEvent.TEST_EXECUTION) private class SetupOverridden { diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java index 886bfc128c..d9b1596a1b 100644 --- a/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java +++ b/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java @@ -35,11 +35,6 @@ public class WithUserDetailsTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_METHOD); } - @WithUserDetails - private static class Annotated { - - } - @Test public void findMergedAnnotationWhenSetupExplicitThenOverridden() { WithSecurityContext context = AnnotatedElementUtils.findMergedAnnotation(SetupExplicit.class, @@ -48,11 +43,6 @@ public class WithUserDetailsTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_METHOD); } - @WithUserDetails(setupBefore = TestExecutionEvent.TEST_METHOD) - private class SetupExplicit { - - } - @Test public void findMergedAnnotationWhenSetupOverriddenThenOverridden() { WithSecurityContext context = AnnotatedElementUtils.findMergedAnnotation(SetupOverridden.class, @@ -61,6 +51,16 @@ public class WithUserDetailsTests { assertThat(context.setupBefore()).isEqualTo(TestExecutionEvent.TEST_EXECUTION); } + @WithUserDetails + private static class Annotated { + + } + + @WithUserDetails(setupBefore = TestExecutionEvent.TEST_METHOD) + private class SetupExplicit { + + } + @WithUserDetails(setupBefore = TestExecutionEvent.TEST_EXECUTION) private class SetupOverridden { diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java index cfdd8d009a..a220845bba 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java @@ -172,6 +172,10 @@ public class SecurityMockMvcRequestPostProcessorsCsrfTests { return new CsrfParamResultMatcher(); } + public static ResultMatcher csrfAsHeader() { + return new CsrfHeaderResultMatcher(); + } + static class CsrfParamResultMatcher implements ResultMatcher { @Override @@ -183,10 +187,6 @@ public class SecurityMockMvcRequestPostProcessorsCsrfTests { } - public static ResultMatcher csrfAsHeader() { - return new CsrfHeaderResultMatcher(); - } - static class CsrfHeaderResultMatcher implements ResultMatcher { @Override diff --git a/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java index 55d5edf3e3..763d2e7ad2 100644 --- a/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java @@ -256,6 +256,21 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo this.springSecurityContextKey = springSecurityContextKey; } + private boolean isTransientAuthentication(Authentication authentication) { + return AnnotationUtils.getAnnotation(authentication.getClass(), Transient.class) != null; + } + + /** + * Sets the {@link AuthenticationTrustResolver} to be used. The default is + * {@link AuthenticationTrustResolverImpl}. + * @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be + * null. + */ + public void setTrustResolver(AuthenticationTrustResolver trustResolver) { + Assert.notNull(trustResolver, "trustResolver cannot be null"); + this.trustResolver = trustResolver; + } + private static class SaveToSessionRequestWrapper extends HttpServletRequestWrapper { private final SaveContextOnUpdateOrErrorResponseWrapper response; @@ -435,19 +450,4 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo } - private boolean isTransientAuthentication(Authentication authentication) { - return AnnotationUtils.getAnnotation(authentication.getClass(), Transient.class) != null; - } - - /** - * Sets the {@link AuthenticationTrustResolver} to be used. The default is - * {@link AuthenticationTrustResolverImpl}. - * @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be - * null. - */ - public void setTrustResolver(AuthenticationTrustResolver trustResolver) { - Assert.notNull(trustResolver, "trustResolver cannot be null"); - this.trustResolver = trustResolver; - } - } diff --git a/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java index 305436fbd1..3ba25039a8 100644 --- a/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java +++ b/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java @@ -82,6 +82,20 @@ public final class ClearSiteDataHeaderWriter implements HeaderWriter { } } + private String transformToHeaderValue(Directive... directives) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < directives.length - 1; i++) { + sb.append(directives[i].headerValue).append(", "); + } + sb.append(directives[directives.length - 1].headerValue); + return sb.toString(); + } + + @Override + public String toString() { + return getClass().getName() + " [headerValue=" + this.headerValue + "]"; + } + /** *

* Represents the directive values expected by the {@link ClearSiteDataHeaderWriter} @@ -104,15 +118,6 @@ public final class ClearSiteDataHeaderWriter implements HeaderWriter { } - private String transformToHeaderValue(Directive... directives) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < directives.length - 1; i++) { - sb.append(directives[i].headerValue).append(", "); - } - sb.append(directives[directives.length - 1].headerValue); - return sb.toString(); - } - private static final class SecureRequestMatcher implements RequestMatcher { @Override @@ -122,9 +127,4 @@ public final class ClearSiteDataHeaderWriter implements HeaderWriter { } - @Override - public String toString() { - return getClass().getName() + " [headerValue=" + this.headerValue + "]"; - } - } diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/SwitchUserWebFilter.java b/web/src/main/java/org/springframework/security/web/server/authentication/SwitchUserWebFilter.java index 82455c1699..e06fbaada5 100644 --- a/web/src/main/java/org/springframework/security/web/server/authentication/SwitchUserWebFilter.java +++ b/web/src/main/java/org/springframework/security/web/server/authentication/SwitchUserWebFilter.java @@ -314,14 +314,6 @@ public class SwitchUserWebFilter implements WebFilter { return new AuthenticationCredentialsNotFoundException("No target user for the given username"); } - private static class SwitchUserAuthenticationException extends RuntimeException { - - SwitchUserAuthenticationException(AuthenticationException exception) { - super(exception); - } - - } - /** * Sets the repository for persisting the SecurityContext. Default is * {@link WebSessionServerSecurityContextRepository} @@ -372,4 +364,12 @@ public class SwitchUserWebFilter implements WebFilter { this.switchUserMatcher = switchUserMatcher; } + private static class SwitchUserAuthenticationException extends RuntimeException { + + SwitchUserAuthenticationException(AuthenticationException exception) { + super(exception); + } + + } + } diff --git a/web/src/main/java/org/springframework/security/web/server/authorization/ServerWebExchangeDelegatingServerAccessDeniedHandler.java b/web/src/main/java/org/springframework/security/web/server/authorization/ServerWebExchangeDelegatingServerAccessDeniedHandler.java index e2fd9dd5b2..38961c513d 100644 --- a/web/src/main/java/org/springframework/security/web/server/authorization/ServerWebExchangeDelegatingServerAccessDeniedHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/authorization/ServerWebExchangeDelegatingServerAccessDeniedHandler.java @@ -84,6 +84,11 @@ public class ServerWebExchangeDelegatingServerAccessDeniedHandler implements Ser this.defaultHandler = accessDeniedHandler; } + private Mono isMatch(ServerWebExchange exchange, DelegateEntry entry) { + ServerWebExchangeMatcher matcher = entry.getMatcher(); + return matcher.matches(exchange).map(ServerWebExchangeMatcher.MatchResult::isMatch); + } + public static class DelegateEntry { private final ServerWebExchangeMatcher matcher; @@ -105,9 +110,4 @@ public class ServerWebExchangeDelegatingServerAccessDeniedHandler implements Ser } - private Mono isMatch(ServerWebExchange exchange, DelegateEntry entry) { - ServerWebExchangeMatcher matcher = entry.getMatcher(); - return matcher.matches(exchange).map(ServerWebExchangeMatcher.MatchResult::isMatch); - } - } diff --git a/web/src/test/java/org/springframework/security/test/web/reactive/server/WebTestHandler.java b/web/src/test/java/org/springframework/security/test/web/reactive/server/WebTestHandler.java index 6eb74cd5c4..07d478e0f9 100644 --- a/web/src/test/java/org/springframework/security/test/web/reactive/server/WebTestHandler.java +++ b/web/src/test/java/org/springframework/security/test/web/reactive/server/WebTestHandler.java @@ -50,6 +50,10 @@ public final class WebTestHandler { return new WebHandlerResult(this.webHandler.exchange); } + public static WebTestHandler bindToWebFilters(WebFilter... filters) { + return new WebTestHandler(filters); + } + public static final class WebHandlerResult { private final ServerWebExchange exchange; @@ -64,10 +68,6 @@ public final class WebTestHandler { } - public static WebTestHandler bindToWebFilters(WebFilter... filters) { - return new WebTestHandler(filters); - } - static class MockWebHandler implements WebHandler { private ServerWebExchange exchange; diff --git a/web/src/test/java/org/springframework/security/web/access/expression/WebExpressionVoterTests.java b/web/src/test/java/org/springframework/security/web/access/expression/WebExpressionVoterTests.java index f08f177a57..608053c1d7 100644 --- a/web/src/test/java/org/springframework/security/web/access/expression/WebExpressionVoterTests.java +++ b/web/src/test/java/org/springframework/security/web/access/expression/WebExpressionVoterTests.java @@ -96,14 +96,6 @@ public class WebExpressionVoterTests { assertThat(voter.supports(FilterInvocationChild.class)).isTrue(); } - private static class FilterInvocationChild extends FilterInvocation { - - FilterInvocationChild(ServletRequest request, ServletResponse response, FilterChain chain) { - super(request, response, chain); - } - - } - @Test public void supportFilterInvocation() { WebExpressionVoter voter = new WebExpressionVoter(); @@ -116,4 +108,12 @@ public class WebExpressionVoterTests { assertThat(voter.supports(Object.class)).isFalse(); } + private static class FilterInvocationChild extends FilterInvocation { + + FilterInvocationChild(ServletRequest request, ServletResponse response, FilterChain chain) { + super(request, response, chain); + } + + } + } diff --git a/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java index ff8e4b3560..ea179bd770 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java @@ -150,26 +150,6 @@ public class DefaultLoginPageGeneratingFilterTests { filter.doFilter(new MockHttpServletRequest("GET", "/login"), new MockHttpServletResponse(), this.chain); } - // Fake OpenID filter (since it's not in this module - @SuppressWarnings("unused") - private static class MockProcessingFilter extends AbstractAuthenticationProcessingFilter { - - MockProcessingFilter() { - super("/someurl"); - } - - @Override - public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) - throws AuthenticationException { - return null; - } - - public String getClaimedIdentityFieldName() { - return "unused"; - } - - } - /* SEC-1111 */ @Test public void handlesNonIso8859CharsInErrorMessage() throws Exception { @@ -218,6 +198,25 @@ public class DefaultLoginPageGeneratingFilterTests { assertThat(response.getContentAsString()).contains("Login with SAML 2.0"); assertThat(response.getContentAsString()) .contains("Google < > " ' &"); + } // Fake OpenID filter (since it's not in this module + + @SuppressWarnings("unused") + private static class MockProcessingFilter extends AbstractAuthenticationProcessingFilter { + + MockProcessingFilter() { + super("/someurl"); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) + throws AuthenticationException { + return null; + } + + public String getClaimedIdentityFieldName() { + return "unused"; + } + } } diff --git a/web/src/test/java/org/springframework/security/web/bind/support/AuthenticationPrincipalArgumentResolverTests.java b/web/src/test/java/org/springframework/security/web/bind/support/AuthenticationPrincipalArgumentResolverTests.java index 3a0344cb33..d55357f9ff 100644 --- a/web/src/test/java/org/springframework/security/web/bind/support/AuthenticationPrincipalArgumentResolverTests.java +++ b/web/src/test/java/org/springframework/security/web/bind/support/AuthenticationPrincipalArgumentResolverTests.java @@ -180,6 +180,12 @@ public class AuthenticationPrincipalArgumentResolverTests { return new MethodParameter(method, 0); } + private void setAuthenticationPrincipal(Object principal) { + this.expectedPrincipal = principal; + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken(this.expectedPrincipal, "password", "ROLE_USER")); + } + @Target({ ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @AuthenticationPrincipal @@ -227,10 +233,4 @@ public class AuthenticationPrincipalArgumentResolverTests { } - private void setAuthenticationPrincipal(Object principal) { - this.expectedPrincipal = principal; - SecurityContextHolder.getContext() - .setAuthentication(new TestingAuthenticationToken(this.expectedPrincipal, "password", "ROLE_USER")); - } - } diff --git a/web/src/test/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.java b/web/src/test/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.java index dd7f1db152..fdaa0cca8d 100644 --- a/web/src/test/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.java +++ b/web/src/test/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializerTests.java @@ -92,11 +92,6 @@ public class AbstractSecurityWebApplicationInitializerTests { verify(context).addListener(any(ContextLoaderListener.class)); } - @Configuration - static class MyRootConfiguration { - - } - @Test public void onStartupWhenEnableHttpSessionEventPublisherIsTrueThenAddsHttpSessionEventPublisher() { ServletContext context = mock(ServletContext.class); @@ -435,4 +430,9 @@ public class AbstractSecurityWebApplicationInitializerTests { assertThat(proxy).hasFieldOrPropertyWithValue("targetBeanName", "springSecurityFilterChain"); } + @Configuration + static class MyRootConfiguration { + + } + } diff --git a/web/src/test/java/org/springframework/security/web/method/ResolvableMethod.java b/web/src/test/java/org/springframework/security/web/method/ResolvableMethod.java index 58c6eccc9b..37fe725548 100644 --- a/web/src/test/java/org/springframework/security/web/method/ResolvableMethod.java +++ b/web/src/test/java/org/springframework/security/web/method/ResolvableMethod.java @@ -250,6 +250,52 @@ public final class ResolvableMethod { return new Builder<>(objectClass); } + @SuppressWarnings("unchecked") + private static T initProxy(Class type, MethodInvocationInterceptor interceptor) { + Assert.notNull(type, "'type' must not be null"); + if (type.isInterface()) { + ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE); + factory.addInterface(type); + factory.addInterface(Supplier.class); + factory.addAdvice(interceptor); + return (T) factory.getProxy(); + } + + else { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(type); + enhancer.setInterfaces(new Class[] { Supplier.class }); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); + enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); + + Class proxyClass = enhancer.createClass(); + Object proxy = null; + + if (objenesis.isWorthTrying()) { + try { + proxy = objenesis.newInstance(proxyClass, enhancer.getUseCache()); + } + catch (ObjenesisException ex) { + logger.debug("Objenesis failed, falling back to default constructor", ex); + } + } + + if (proxy == null) { + try { + proxy = ReflectionUtils.accessibleConstructor(proxyClass).newInstance(); + } + catch (Throwable ex) { + throw new IllegalStateException( + "Unable to instantiate proxy " + "via both Objenesis and default constructor fails as well", + ex); + } + } + + ((Factory) proxy).setCallbacks(new Callback[] { interceptor }); + return (T) proxy; + } + } + /** * Builder for {@code ResolvableMethod}. */ @@ -613,50 +659,4 @@ public final class ResolvableMethod { } - @SuppressWarnings("unchecked") - private static T initProxy(Class type, MethodInvocationInterceptor interceptor) { - Assert.notNull(type, "'type' must not be null"); - if (type.isInterface()) { - ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE); - factory.addInterface(type); - factory.addInterface(Supplier.class); - factory.addAdvice(interceptor); - return (T) factory.getProxy(); - } - - else { - Enhancer enhancer = new Enhancer(); - enhancer.setSuperclass(type); - enhancer.setInterfaces(new Class[] { Supplier.class }); - enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); - enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); - - Class proxyClass = enhancer.createClass(); - Object proxy = null; - - if (objenesis.isWorthTrying()) { - try { - proxy = objenesis.newInstance(proxyClass, enhancer.getUseCache()); - } - catch (ObjenesisException ex) { - logger.debug("Objenesis failed, falling back to default constructor", ex); - } - } - - if (proxy == null) { - try { - proxy = ReflectionUtils.accessibleConstructor(proxyClass).newInstance(); - } - catch (Throwable ex) { - throw new IllegalStateException( - "Unable to instantiate proxy " + "via both Objenesis and default constructor fails as well", - ex); - } - } - - ((Factory) proxy).setCallbacks(new Callback[] { interceptor }); - return (T) proxy; - } - } - } diff --git a/web/src/test/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolverTests.java b/web/src/test/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolverTests.java index 9d5af585de..c4a5545f84 100644 --- a/web/src/test/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolverTests.java +++ b/web/src/test/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolverTests.java @@ -204,6 +204,12 @@ public class AuthenticationPrincipalArgumentResolverTests { return new MethodParameter(method, 0); } + private void setAuthenticationPrincipal(Object principal) { + this.expectedPrincipal = principal; + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken(this.expectedPrincipal, "password", "ROLE_USER")); + } + @Target({ ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @AuthenticationPrincipal @@ -305,10 +311,4 @@ public class AuthenticationPrincipalArgumentResolverTests { } - private void setAuthenticationPrincipal(Object principal) { - this.expectedPrincipal = principal; - SecurityContextHolder.getContext() - .setAuthentication(new TestingAuthenticationToken(this.expectedPrincipal, "password", "ROLE_USER")); - } - } diff --git a/web/src/test/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolverTests.java b/web/src/test/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolverTests.java index 61d4f06744..e2c94bfa5f 100644 --- a/web/src/test/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolverTests.java +++ b/web/src/test/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolverTests.java @@ -259,6 +259,23 @@ public class CurrentSecurityContextArgumentResolverTests { return new MethodParameter(method, 0); } + private void setAuthenticationPrincipal(Object principal) { + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken(principal, "password", "ROLE_USER")); + } + + private void setAuthenticationPrincipalWithCustomSecurityContext(Object principal) { + CustomSecurityContext csc = new CustomSecurityContext(); + csc.setAuthentication(new TestingAuthenticationToken(principal, "password", "ROLE_USER")); + SecurityContextHolder.setContext(csc); + } + + private void setAuthenticationDetail(Object detail) { + TestingAuthenticationToken tat = new TestingAuthenticationToken("user", "password", "ROLE_USER"); + tat.setDetails(detail); + SecurityContextHolder.getContext().setAuthentication(tat); + } + public static class TestController { public void showSecurityContextNoAnnotation(String user) { @@ -317,17 +334,6 @@ public class CurrentSecurityContextArgumentResolverTests { } - private void setAuthenticationPrincipal(Object principal) { - SecurityContextHolder.getContext() - .setAuthentication(new TestingAuthenticationToken(principal, "password", "ROLE_USER")); - } - - private void setAuthenticationPrincipalWithCustomSecurityContext(Object principal) { - CustomSecurityContext csc = new CustomSecurityContext(); - csc.setAuthentication(new TestingAuthenticationToken(principal, "password", "ROLE_USER")); - SecurityContextHolder.setContext(csc); - } - static class CustomSecurityContext implements SecurityContext { private Authentication authentication; @@ -365,10 +371,4 @@ public class CurrentSecurityContextArgumentResolverTests { } - private void setAuthenticationDetail(Object detail) { - TestingAuthenticationToken tat = new TestingAuthenticationToken("user", "password", "ROLE_USER"); - tat.setDetails(detail); - SecurityContextHolder.getContext().setAuthentication(tat); - } - } diff --git a/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java b/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java index a6e3c40c26..f138550b42 100644 --- a/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java +++ b/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java @@ -348,6 +348,10 @@ public class CurrentSecurityContextArgumentResolverTests { @CurrentSecurityWithErrorOnInvalidType Mono typeMisMatch) { } + private Authentication buildAuthenticationWithPrincipal(Object principal) { + return new TestingAuthenticationToken(principal, "password", "ROLE_USER"); + } + @Target({ ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @CurrentSecurityContext @@ -389,8 +393,4 @@ public class CurrentSecurityContextArgumentResolverTests { } - private Authentication buildAuthenticationWithPrincipal(Object principal) { - return new TestingAuthenticationToken(principal, "password", "ROLE_USER"); - } - } diff --git a/web/src/test/java/org/springframework/security/web/util/ThrowableAnalyzerTests.java b/web/src/test/java/org/springframework/security/web/util/ThrowableAnalyzerTests.java index 390aae5c85..1c6fa7efb6 100644 --- a/web/src/test/java/org/springframework/security/web/util/ThrowableAnalyzerTests.java +++ b/web/src/test/java/org/springframework/security/web/util/ThrowableAnalyzerTests.java @@ -31,39 +31,6 @@ import static org.assertj.core.api.Assertions.fail; @SuppressWarnings("unchecked") public class ThrowableAnalyzerTests { - /** - * Exception for testing purposes. The cause is not retrievable by {@link #getCause()} - * . - */ - public static final class NonStandardException extends Exception { - - private Throwable cause; - - public NonStandardException(String message, Throwable cause) { - super(message); - this.cause = cause; - } - - public Throwable resolveCause() { - return this.cause; - } - - } - - /** - * ThrowableCauseExtractor for handling NonStandardException - * instances. - */ - public static final class NonStandardExceptionCauseExtractor implements ThrowableCauseExtractor { - - @Override - public Throwable extractCause(Throwable throwable) { - ThrowableAnalyzer.verifyThrowableHierarchy(throwable, NonStandardException.class); - return ((NonStandardException) throwable).resolveCause(); - } - - } - /** * An array of nested throwables for testing. The cause of element 0 is element 1, the * cause of element 1 is element 2 and so on. @@ -282,4 +249,37 @@ public class ThrowableAnalyzerTests { } } + /** + * Exception for testing purposes. The cause is not retrievable by {@link #getCause()} + * . + */ + public static final class NonStandardException extends Exception { + + private Throwable cause; + + public NonStandardException(String message, Throwable cause) { + super(message); + this.cause = cause; + } + + public Throwable resolveCause() { + return this.cause; + } + + } + + /** + * ThrowableCauseExtractor for handling NonStandardException + * instances. + */ + public static final class NonStandardExceptionCauseExtractor implements ThrowableCauseExtractor { + + @Override + public Throwable extractCause(Throwable throwable) { + ThrowableAnalyzer.verifyThrowableHierarchy(throwable, NonStandardException.class); + return ((NonStandardException) throwable).resolveCause(); + } + + } + }