2
0
Эх сурвалжийг харах

DSL nested builder for HTTP security

DSL nested builder for HTTP security

Fixes gh-5557
Rob Winch 6 жил өмнө
parent
commit
ea54d9014d
61 өөрчлөгдсөн 4902 нэмэгдсэн , 536 устгасан
  1. 911 20
      config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
  2. 187 1
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java
  3. 40 0
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java
  4. 16 1
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java
  5. 57 0
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
  6. 40 5
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
  7. 70 2
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurer.java
  8. 98 8
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
  9. 226 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
  10. 23 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
  11. 153 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
  12. 65 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
  13. 81 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
  14. 43 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
  15. 150 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
  16. 338 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
  17. 4 3
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
  18. 118 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
  19. 114 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
  20. 88 2
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
  21. 12 9
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
  22. 74 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
  23. 60 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
  24. 58 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
  25. 80 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
  26. 90 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
  27. 33 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
  28. 101 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
  29. 48 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
  30. 116 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
  31. 64 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
  32. 40 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java
  33. 183 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
  34. 183 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
  35. 178 0
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
  36. 8 4
      docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/mvc.adoc
  37. 107 61
      docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/oauth2.adoc
  38. 5 3
      docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc
  39. 116 86
      docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
  40. 41 24
      docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-client.adoc
  41. 15 12
      docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-login.adoc
  42. 2 2
      docs/manual/src/docs/asciidoc/_includes/servlet/web/cors.adoc
  43. 11 5
      docs/manual/src/docs/asciidoc/_includes/servlet/web/csrf.adoc
  44. 179 124
      docs/manual/src/docs/asciidoc/_includes/servlet/web/headers.adoc
  45. 23 14
      docs/manual/src/docs/asciidoc/_includes/servlet/web/websocket.adoc
  46. 11 6
      samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  47. 16 10
      samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
  48. 12 7
      samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
  49. 9 6
      samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
  50. 13 8
      samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
  51. 11 7
      samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
  52. 12 7
      samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
  53. 11 10
      samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java
  54. 16 9
      samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  55. 15 11
      samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  56. 66 41
      samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  57. 10 7
      samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  58. 14 10
      samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  59. 8 5
      samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
  60. 10 0
      web/src/main/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriter.java
  61. 19 0
      web/src/test/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriterTests.java

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 911 - 20
config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java


+ 187 - 1
config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -30,6 +31,8 @@ import org.springframework.security.web.header.HeaderWriter;
 import org.springframework.security.web.header.HeaderWriterFilter;
 import org.springframework.security.web.header.writers.*;
 import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
+import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter;
+import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;
 import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
 import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
 import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -121,6 +124,26 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return contentTypeOptions.enable();
 	}
 
+	/**
+	 * Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the <a href=
+	 * "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
+	 * >X-Content-Type-Options</a>:
+	 *
+	 * <pre>
+	 * X-Content-Type-Options: nosniff
+	 * </pre>
+	 *
+	 * @param contentTypeOptionsCustomizer the {@link Customizer} to provide more options for
+	 * the {@link ContentTypeOptionsConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> contentTypeOptions(Customizer<ContentTypeOptionsConfig> contentTypeOptionsCustomizer)
+			throws Exception {
+		contentTypeOptionsCustomizer.customize(contentTypeOptions.enable());
+		return HeadersConfigurer.this;
+	}
+
 	public final class ContentTypeOptionsConfig {
 		private XContentTypeOptionsHeaderWriter writer;
 
@@ -174,6 +197,25 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return xssProtection.enable();
 	}
 
+	/**
+	 * <strong>Note this is not comprehensive XSS protection!</strong>
+	 *
+	 * <p>
+	 * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
+	 * "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
+	 * >X-XSS-Protection header</a>
+	 * </p>
+	 *
+	 * @param xssCustomizer the {@link Customizer} to provide more options for
+	 * the {@link XXssConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> xssProtection(Customizer<XXssConfig> xssCustomizer) throws Exception {
+		xssCustomizer.customize(xssProtection.enable());
+		return HeadersConfigurer.this;
+	}
+
 	public final class XXssConfig {
 		private XXssProtectionHeaderWriter writer;
 
@@ -268,6 +310,26 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return cacheControl.enable();
 	}
 
+	/**
+	 * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
+	 * following headers:
+	 * <ul>
+	 * <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
+	 * <li>Pragma: no-cache</li>
+	 * <li>Expires: 0</li>
+	 * </ul>
+	 *
+	 * @param cacheControlCustomizer the {@link Customizer} to provide more options for
+	 * the {@link CacheControlConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> cacheControl(Customizer<CacheControlConfig> cacheControlCustomizer) throws Exception {
+		cacheControlCustomizer.customize(cacheControl.enable());
+		return HeadersConfigurer.this;
+	}
+
+
 	public final class CacheControlConfig {
 		private CacheControlHeadersWriter writer;
 
@@ -319,6 +381,21 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return hsts.enable();
 	}
 
+	/**
+	 * Allows customizing the {@link HstsHeaderWriter} which provides support for <a
+	 * href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
+	 * (HSTS)</a>.
+	 *
+	 * @param hstsCustomizer the {@link Customizer} to provide more options for
+	 * the {@link HstsConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> httpStrictTransportSecurity(Customizer<HstsConfig> hstsCustomizer) throws Exception {
+		hstsCustomizer.customize(hsts.enable());
+		return HeadersConfigurer.this;
+	}
+
 	public final class HstsConfig {
 		private HstsHeaderWriter writer;
 
@@ -440,6 +517,19 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return 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
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> frameOptions(Customizer<FrameOptionsConfig> frameOptionsCustomizer) throws Exception {
+		frameOptionsCustomizer.customize(frameOptions.enable());
+		return HeadersConfigurer.this;
+	}
+
 	public final class FrameOptionsConfig {
 		private XFrameOptionsHeaderWriter writer;
 
@@ -516,6 +606,20 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return hpkp.enable();
 	}
 
+	/**
+	 * Allows customizing the {@link HpkpHeaderWriter} which provides support for <a
+	 * href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
+	 *
+	 * @param hpkpCustomizer the {@link Customizer} to provide more options for
+	 * the {@link HpkpConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> httpPublicKeyPinning(Customizer<HpkpConfig> hpkpCustomizer) throws Exception {
+		hpkpCustomizer.customize(hpkp.enable());
+		return HeadersConfigurer.this;
+	}
+
 	public final class HpkpConfig {
 		private HpkpHeaderWriter writer;
 
@@ -713,12 +817,57 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return contentSecurityPolicy;
 	}
 
+	/**
+	 * <p>
+	 * Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security Policy (CSP) Level 2</a>.
+	 * </p>
+	 *
+	 * <p>
+	 * Calling this method automatically enables (includes) the Content-Security-Policy header in the response
+	 * using the supplied security policy directive(s).
+	 * </p>
+	 *
+	 * <p>
+	 * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports the writing
+	 * of the two headers as detailed in the W3C Candidate Recommendation:
+	 * </p>
+	 * <ul>
+	 * 	<li>Content-Security-Policy</li>
+	 * 	<li>Content-Security-Policy-Report-Only</li>
+	 * </ul>
+	 *
+	 * @see ContentSecurityPolicyHeaderWriter
+	 * @param contentSecurityCustomizer the {@link Customizer} to provide more options for
+	 * the {@link ContentSecurityPolicyConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> contentSecurityPolicy(Customizer<ContentSecurityPolicyConfig> contentSecurityCustomizer)
+			throws Exception {
+		this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter();
+		contentSecurityCustomizer.customize(this.contentSecurityPolicy);
+
+		return HeadersConfigurer.this;
+	}
+
 	public final class ContentSecurityPolicyConfig {
 		private ContentSecurityPolicyHeaderWriter writer;
 
 		private ContentSecurityPolicyConfig() {
 		}
 
+		/**
+		 * Sets the security policy directive(s) to be used in the response header.
+		 *
+		 * @param policyDirectives the security policy directive(s)
+		 * @return the {@link ContentSecurityPolicyConfig} for additional configuration
+		 * @throws IllegalArgumentException if policyDirectives is null or empty
+		 */
+		public ContentSecurityPolicyConfig policyDirectives(String policyDirectives) {
+			this.writer.setPolicyDirectives(policyDirectives);
+			return this;
+		}
+
 		/**
 		 * Enables (includes) the Content-Security-Policy-Report-Only header in the response.
 		 *
@@ -860,6 +1009,31 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		return this.referrerPolicy;
 	}
 
+	/**
+	 * <p>
+	 * Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
+	 * </p>
+	 *
+	 * <p>
+	 * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
+	 * of the header as detailed in the W3C Technical Report:
+	 * </p>
+	 * <ul>
+	 *  <li>Referrer-Policy</li>
+	 * </ul>
+	 *
+	 * @see ReferrerPolicyHeaderWriter
+	 * @param referrerPolicyCustomizer the {@link Customizer} to provide more options for
+	 * the {@link ReferrerPolicyConfig}
+	 * @return the {@link HeadersConfigurer} for additional customizations
+	 * @throws Exception
+	 */
+	public HeadersConfigurer<H> referrerPolicy(Customizer<ReferrerPolicyConfig> referrerPolicyCustomizer) throws Exception {
+		this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
+		referrerPolicyCustomizer.customize(this.referrerPolicy);
+		return HeadersConfigurer.this;
+	}
+
 	public final class ReferrerPolicyConfig {
 
 		private ReferrerPolicyHeaderWriter writer;
@@ -867,6 +1041,18 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		private ReferrerPolicyConfig() {
 		}
 
+		/**
+		 * Sets the policy to be used in the response header.
+		 *
+		 * @param policy a referrer policy
+		 * @return the {@link ReferrerPolicyConfig} for additional configuration
+		 * @throws IllegalArgumentException if policy is null
+		 */
+		public ReferrerPolicyConfig policy(ReferrerPolicy policy) {
+			this.writer.setPolicy(policy);
+			return this;
+		}
+
 		public HeadersConfigurer<H> and() {
 			return HeadersConfigurer.this;
 		}

+ 40 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java

@@ -26,6 +26,7 @@ import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.GenericApplicationListenerAdapter;
 import org.springframework.context.event.SmartApplicationListener;
 import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.http.SessionCreationPolicy;
@@ -249,6 +250,19 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
 		return new SessionFixationConfigurer();
 	}
 
+	/**
+	 * Allows configuring session fixation protection.
+	 *
+	 * @param sessionFixationCustomizer the {@link Customizer} to provide more options for
+	 * the {@link SessionFixationConfigurer}
+	 * @return the {@link SessionManagementConfigurer} for further customizations
+	 */
+	public SessionManagementConfigurer<H> sessionFixation(Customizer<SessionFixationConfigurer> sessionFixationCustomizer)
+			throws Exception {
+		sessionFixationCustomizer.customize(new SessionFixationConfigurer());
+		return this;
+	}
+
 	/**
 	 * Controls the maximum number of sessions for a user. The default is to allow any
 	 * number of users.
@@ -260,6 +274,20 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
 		return new ConcurrencyControlConfigurer();
 	}
 
+	/**
+	 * Controls the maximum number of sessions for a user. The default is to allow any
+	 * number of users.
+	 *
+	 * @param sessionConcurrencyCustomizer the {@link Customizer} to provide more options for
+	 * the {@link ConcurrencyControlConfigurer}
+	 * @return the {@link SessionManagementConfigurer} for further customizations
+	 */
+	public SessionManagementConfigurer<H> sessionConcurrency(Customizer<ConcurrencyControlConfigurer> sessionConcurrencyCustomizer)
+			throws Exception {
+		sessionConcurrencyCustomizer.customize(new ConcurrencyControlConfigurer());
+		return this;
+	}
+
 	/**
 	 * Invokes {@link #postProcess(Object)} and sets the
 	 * {@link SessionAuthenticationStrategy} for session fixation.
@@ -338,6 +366,18 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
 	 */
 	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

+ 16 - 1
config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
 package org.springframework.security.config.annotation.web.configurers.oauth2.client;
 
 import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
 import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
@@ -135,6 +136,20 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
 		return this.authorizationCodeGrantConfigurer;
 	}
 
+	/**
+	 * Configures the OAuth 2.0 Authorization Code Grant.
+	 *
+	 * @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more options for
+	 * the {@link AuthorizationCodeGrantConfigurer}
+	 * @return the {@link OAuth2ClientConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2ClientConfigurer<B> authorizationCodeGrant(Customizer<AuthorizationCodeGrantConfigurer> authorizationCodeGrantCustomizer)
+			throws Exception {
+		authorizationCodeGrantCustomizer.customize(this.authorizationCodeGrantConfigurer);
+		return this;
+	}
+
 	/**
 	 * Configuration options for the OAuth 2.0 Authorization Code Grant.
 	 */

+ 57 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java

@@ -20,6 +20,7 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.ResolvableType;
 import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
@@ -201,6 +202,20 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
 		return this.authorizationEndpointConfig;
 	}
 
+	/**
+	 * Configures the Authorization Server's Authorization Endpoint.
+	 *
+	 * @param authorizationEndpointCustomizer the {@link Customizer} to provide more options for
+	 * the {@link AuthorizationEndpointConfig}
+	 * @return the {@link OAuth2LoginConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2LoginConfigurer<B> authorizationEndpoint(Customizer<AuthorizationEndpointConfig> authorizationEndpointCustomizer)
+			throws Exception {
+		authorizationEndpointCustomizer.customize(this.authorizationEndpointConfig);
+		return this;
+	}
+
 	/**
 	 * Configuration options for the Authorization Server's Authorization Endpoint.
 	 */
@@ -268,6 +283,20 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
 		return this.tokenEndpointConfig;
 	}
 
+	/**
+	 * Configures the Authorization Server's Token Endpoint.
+	 *
+	 * @param tokenEndpointCustomizer the {@link Customizer} to provide more options for
+	 * the {@link TokenEndpointConfig}
+	 * @return the {@link OAuth2LoginConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2LoginConfigurer<B> tokenEndpoint(Customizer<TokenEndpointConfig> tokenEndpointCustomizer)
+			throws Exception {
+		tokenEndpointCustomizer.customize(this.tokenEndpointConfig);
+		return this;
+	}
+
 	/**
 	 * Configuration options for the Authorization Server's Token Endpoint.
 	 */
@@ -310,6 +339,20 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
 		return this.redirectionEndpointConfig;
 	}
 
+	/**
+	 * Configures the Client's Redirection Endpoint.
+	 *
+	 * @param redirectionEndpointCustomizer the {@link Customizer} to provide more options for
+	 * the {@link RedirectionEndpointConfig}
+	 * @return the {@link OAuth2LoginConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2LoginConfigurer<B> redirectionEndpoint(Customizer<RedirectionEndpointConfig> redirectionEndpointCustomizer)
+			throws Exception {
+		redirectionEndpointCustomizer.customize(this.redirectionEndpointConfig);
+		return this;
+	}
+
 	/**
 	 * Configuration options for the Client's Redirection Endpoint.
 	 */
@@ -350,6 +393,20 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
 		return this.userInfoEndpointConfig;
 	}
 
+	/**
+	 * Configures the Authorization Server's UserInfo Endpoint.
+	 *
+	 * @param userInfoEndpointCustomizer the {@link Customizer} to provide more options for
+	 * the {@link UserInfoEndpointConfig}
+	 * @return the {@link OAuth2LoginConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2LoginConfigurer<B> userInfoEndpoint(Customizer<UserInfoEndpointConfig> userInfoEndpointCustomizer)
+			throws Exception {
+		userInfoEndpointCustomizer.customize(this.userInfoEndpointConfig);
+		return this;
+	}
+
 	/**
 	 * Configuration options for the Authorization Server's UserInfo Endpoint.
 	 */

+ 40 - 5
config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java

@@ -25,6 +25,7 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.AuthenticationManagerResolver;
 import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
 import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
 import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
@@ -65,11 +66,12 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
  * <li>{@link #accessDeniedHandler(AccessDeniedHandler)}</li> - customizes how access denied errors are handled
  * <li>{@link #authenticationEntryPoint(AuthenticationEntryPoint)}</li> - customizes how authentication failures are handled
  * <li>{@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a bearer token from the request</li>
- * <li>{@link #jwt()} - enables Jwt-encoded bearer token support</li>
+ * <li>{@link #jwt(Customizer)} - enables Jwt-encoded bearer token support</li>
+ * <li>{@link #opaqueToken(Customizer)} - enables opaque bearer token support</li>
  * </ul>
  *
  * <p>
- * When using {@link #jwt()}, either
+ * When using {@link #jwt(Customizer)}, either
  *
  * <ul>
  * <li>
@@ -83,7 +85,7 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
  * </li>
  * </ul>
  *
- * Also with {@link #jwt()} consider
+ * Also with {@link #jwt(Customizer)} consider
  *
  * <ul>
  * <li>
@@ -93,12 +95,12 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
  * </ul>
  *
  * <p>
- * When using {@link #opaque()}, supply an introspection endpoint and its authentication configuration
+ * When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint and its authentication configuration
  * </p>
  *
  * <h2>Security Filters</h2>
  *
- * The following {@code Filter}s are populated when {@link #jwt()} is configured:
+ * The following {@code Filter}s are populated when {@link #jwt(Customizer)} is configured:
  *
  * <ul>
  * <li>{@link BearerTokenAuthenticationFilter}</li>
@@ -180,6 +182,22 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
 		return this.jwtConfigurer;
 	}
 
+	/**
+	 * Enables Jwt-encoded bearer token support.
+	 *
+	 * @param jwtCustomizer the {@link Customizer} to provide more options for
+	 * the {@link JwtConfigurer}
+	 * @return the {@link OAuth2ResourceServerConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2ResourceServerConfigurer<H> jwt(Customizer<JwtConfigurer> jwtCustomizer) throws Exception {
+		if ( this.jwtConfigurer == null ) {
+			this.jwtConfigurer = new JwtConfigurer(this.context);
+		}
+		jwtCustomizer.customize(this.jwtConfigurer);
+		return this;
+	}
+
 	public OpaqueTokenConfigurer opaqueToken() {
 		if (this.opaqueTokenConfigurer == null) {
 			this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
@@ -188,6 +206,23 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
 		return this.opaqueTokenConfigurer;
 	}
 
+	/**
+	 * Enables opaque bearer token support.
+	 *
+	 * @param opaqueTokenCustomizer the {@link Customizer} to provide more options for
+	 * the {@link OpaqueTokenConfigurer}
+	 * @return the {@link OAuth2ResourceServerConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OAuth2ResourceServerConfigurer<H> opaqueToken(Customizer<OpaqueTokenConfigurer> opaqueTokenCustomizer)
+			throws Exception {
+		if (this.opaqueTokenConfigurer == null) {
+			this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
+		}
+		opaqueTokenCustomizer.customize(this.opaqueTokenConfigurer);
+		return this;
+	}
+
 	@Override
 	public void init(H http) throws Exception {
 		registerDefaultAccessDeniedHandler(http);

+ 70 - 2
config/src/main/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurer.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import org.openid4java.consumer.ConsumerManager;
 
 import org.springframework.security.authentication.AuthenticationDetailsSource;
 import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -148,6 +149,24 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
 		return attributeExchangeConfigurer;
 	}
 
+	/**
+	 * Sets up OpenID attribute exchange for OpenIDs matching the specified pattern.
+	 * The default pattern is &quot;.*&quot;, it can be specified using
+	 * {@link AttributeExchangeConfigurer#identifierPattern(String)}
+	 *
+	 * @param attributeExchangeCustomizer the {@link Customizer} to provide more options for
+	 * the {@link AttributeExchangeConfigurer}
+	 * @return a {@link OpenIDLoginConfigurer} for further customizations
+	 * @throws Exception
+	 */
+	public OpenIDLoginConfigurer<H> attributeExchange(Customizer<AttributeExchangeConfigurer> attributeExchangeCustomizer)
+			throws Exception {
+		AttributeExchangeConfigurer attributeExchangeConfigurer = new AttributeExchangeConfigurer(".*");
+		attributeExchangeCustomizer.customize(attributeExchangeConfigurer);
+		this.attributeExchangeConfigurers.add(attributeExchangeConfigurer);
+		return this;
+	}
+
 	/**
 	 * Allows specifying the {@link OpenIDConsumer} to be used. The default is using an
 	 * {@link OpenID4JavaConsumer}.
@@ -373,7 +392,7 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
 	 * @author Rob Winch
 	 */
 	public final class AttributeExchangeConfigurer {
-		private final String identifier;
+		private String identifier;
 		private List<OpenIDAttribute> attributes = new ArrayList<>();
 		private List<AttributeConfigurer> attributeConfigurers = new ArrayList<>();
 
@@ -395,6 +414,19 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
 			return OpenIDLoginConfigurer.this;
 		}
 
+		/**
+		 * Sets the regular expression for matching on OpenID's (i.e.
+		 * "https://www.google.com/.*", ".*yahoo.com.*", etc)
+		 *
+		 * @param identifierPattern the regular expression for matching on OpenID's
+		 * @return the {@link AttributeExchangeConfigurer} for further customization of
+		 * attribute exchange
+		 */
+		public AttributeExchangeConfigurer identifierPattern(String identifierPattern) {
+			this.identifier = identifierPattern;
+			return this;
+		}
+
 		/**
 		 * Adds an {@link OpenIDAttribute} to be obtained for the configured OpenID
 		 * pattern.
@@ -419,6 +451,22 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
 			return attributeConfigurer;
 		}
 
+		/**
+		 * Adds an {@link OpenIDAttribute} named &quot;default-attribute&quot;.
+		 * The name can by updated using {@link AttributeConfigurer#name(String)}.
+		 *
+		 * @param attributeCustomizer the {@link Customizer} to provide more options for
+		 * the {@link AttributeConfigurer}
+		 * @return a {@link AttributeExchangeConfigurer} for further customizations
+		 * @throws Exception
+		 */
+		public AttributeExchangeConfigurer attribute(Customizer<AttributeConfigurer> attributeCustomizer) throws Exception {
+			AttributeConfigurer attributeConfigurer = new AttributeConfigurer();
+			attributeCustomizer.customize(attributeConfigurer);
+			this.attributeConfigurers.add(attributeConfigurer);
+			return this;
+		}
+
 		/**
 		 * Gets the {@link OpenIDAttribute}'s for the configured OpenID pattern
 		 * @return
@@ -443,6 +491,16 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
 			private boolean required = false;
 			private String type;
 
+			/**
+			 * Creates a new instance named "default-attribute".
+			 * The name can by updated using {@link #name(String)}.
+			 *
+			 * @see AttributeExchangeConfigurer#attribute(String)
+			 */
+			private AttributeConfigurer() {
+				this.name = "default-attribute";
+			}
+
 			/**
 			 * Creates a new instance
 			 * @param name the name of the attribute
@@ -486,6 +544,16 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
 				return this;
 			}
 
+			/**
+			 * The OpenID attribute name.
+			 * @param name
+			 * @return the {@link AttributeConfigurer} for further customizations
+			 */
+			public AttributeConfigurer name(String name) {
+				this.name = name;
+				return this;
+			}
+
 			/**
 			 * Gets the {@link AttributeExchangeConfigurer} for further customization of
 			 * the attributes

+ 98 - 8
config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,18 +18,22 @@ package org.springframework.security.config.annotation.web.configurers;
 import org.junit.Rule;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
 import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.core.userdetails.PasswordEncodedUser;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 /**
  * @author Rob Winch
@@ -44,7 +48,7 @@ public class AnonymousConfigurerTests {
 
 	@Test
 	public void requestWhenAnonymousTwiceInvokedThenDoesNotOverride() throws Exception {
-		this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
+		this.spring.register(InvokeTwiceDoesNotOverride.class, PrincipalController.class).autowire();
 
 		this.mockMvc.perform(get("/"))
 			.andExpect(content().string("principal"));
@@ -63,13 +67,99 @@ public class AnonymousConfigurerTests {
 					.and()
 				.anonymous();
 		}
+	}
+
+	@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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.anonymous(anonymous ->
+					anonymous
+						.principal("principal")
+				);
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().permitAll()
+				)
+				.anonymous(AbstractHttpConfigurer::disable);
+			// @formatter:on
+		}
+
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().permitAll()
+				)
+				.anonymous(withDefaults());
+			// @formatter:on
+		}
+
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
 
-		@RestController
-		static class PrincipalController {
-			@GetMapping("/")
-			String principal(@AuthenticationPrincipal String principal) {
-				return principal;
-			}
+	@RestController
+	static class PrincipalController {
+		@GetMapping("/")
+		String principal(@AuthenticationPrincipal String principal) {
+			return principal;
 		}
 	}
 }

+ 226 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.spy;
+import static org.springframework.security.config.Customizer.withDefaults;
 
 /**
  * @author Rob Winch
@@ -113,6 +114,39 @@ public class AuthorizeRequestsTests {
 		}
 	}
 
+	@Test
+	public void postWhenPostDenyAllInLambdaThenRespondsWithForbidden() throws Exception {
+		loadConfig(AntMatchersNoPatternsInLambdaConfig.class);
+		this.request.setMethod("POST");
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		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 {
@@ -314,6 +348,66 @@ public class AuthorizeRequestsTests {
 		}
 	}
 
+	@Test
+	public void requestWhenMvcMatcherDenyAllThenRespondsWithUnauthorized() throws Exception {
+		loadConfig(MvcMatcherInLambdaConfig.class);
+
+		this.request.setRequestURI("/path");
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+		assertThat(this.response.getStatus())
+				.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+		setup();
+
+		this.request.setRequestURI("/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
+	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);
@@ -391,6 +485,85 @@ public class AuthorizeRequestsTests {
 		}
 	}
 
+	@Test
+	public void requestWhenMvcMatcherServletPathDenyAllThenMatchesOnServletPath() throws Exception {
+		loadConfig(MvcMatcherServletPathInLambdaConfig.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 MvcMatcherServletPathInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic(withDefaults())
+				.authorizeRequests(authorizeRequests ->
+					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 mvcMatcherPathVariables() throws Exception {
 		loadConfig(MvcMatcherPathVariablesConfig.class);
@@ -441,6 +614,58 @@ 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
+	static class MvcMatcherPathVariablesInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.httpBasic(withDefaults())
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.mvcMatchers("/user/{userName}").access("#userName == 'user'")
+				);
+			// @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

+ 23 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java

@@ -135,4 +135,27 @@ public class ChannelSecurityConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@Test
+	public void requestWhenRequiresChannelConfiguredInLambdaThenRedirectsToHttps() throws Exception {
+		this.spring.register(RequiresChannelInLambdaConfig.class).autowire();
+
+		mvc.perform(get("/"))
+				.andExpect(redirectedUrl("https://localhost/"));
+	}
+
+	@EnableWebSecurity
+	static class RequiresChannelInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requiresChannel(requiresChannel ->
+					requiresChannel
+						.anyRequest().requiresSecure()
+			);
+			// @formatter:on
+		}
+	}
 }

+ 153 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java

@@ -42,6 +42,7 @@ import java.util.Arrays;
 import java.util.Collections;
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -131,6 +132,56 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.cors(withDefaults());
+			// @formatter:on
+		}
+
+		@RestController
+		@CrossOrigin(methods = {
+				RequestMethod.GET, RequestMethod.POST
+		})
+		static class CorsController {
+			@RequestMapping("/")
+			String hello() {
+				return "Hello";
+			}
+		}
+	}
+
 	@Test
 	public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
 		this.spring.register(ConfigSourceConfig.class).autowire();
@@ -180,6 +231,58 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.cors(withDefaults());
+			// @formatter:on
+		}
+
+		@Bean
+		CorsConfigurationSource corsConfigurationSource() {
+			UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+			CorsConfiguration corsConfiguration = new CorsConfiguration();
+			corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
+			corsConfiguration.setAllowedMethods(Arrays.asList(
+					RequestMethod.GET.name(),
+					RequestMethod.POST.name()));
+			source.registerCorsConfiguration("/**", corsConfiguration);
+			return source;
+		}
+	}
+
 	@Test
 	public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
 		this.spring.register(CorsFilterConfig.class).autowire();
@@ -228,4 +331,54 @@ public class CorsConfigurerTests {
 			return new CorsFilter(source);
 		}
 	}
+
+	@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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.cors(withDefaults());
+			// @formatter:on
+		}
+
+		@Bean
+		CorsFilter corsFilter() {
+			UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+			CorsConfiguration corsConfiguration = new CorsConfiguration();
+			corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
+			corsConfiguration.setAllowedMethods(Arrays.asList(
+					RequestMethod.GET.name(),
+					RequestMethod.POST.name()));
+			source.registerCorsConfiguration("/**", corsConfiguration);
+			return new CorsFilter(source);
+		}
+	}
 }

+ 65 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -75,6 +75,36 @@ 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 {
+		RequestMatcher requestMatcher =
+				request -> HttpMethod.POST.name().equals(request.getMethod());
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf(csrf ->
+					csrf
+						.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
+						.ignoringRequestMatchers(this.requestMatcher)
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers()
 			throws Exception {
@@ -107,6 +137,40 @@ 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 {
+		RequestMatcher requestMatcher =
+				request -> HttpMethod.POST.name().equals(request.getMethod());
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.csrf(csrf ->
+					csrf
+						.ignoringAntMatchers("/no-csrf")
+						.ignoringRequestMatchers(this.requestMatcher)
+				);
+			// @formatter:on
+		}
+	}
+
 	@RestController
 	public static class BasicController {
 		@RequestMapping("/path")

+ 81 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java

@@ -55,6 +55,7 @@ import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
 import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -210,6 +211,26 @@ public class CsrfConfigurerTests {
 		}
 	}
 
+	@Test
+	public void postWhenCsrfDisabledInLambdaThenRespondsWithOk() throws Exception {
+		this.spring.register(DisableCsrfInLambdaConfig.class, BasicController.class).autowire();
+
+		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 {
@@ -386,6 +407,40 @@ public class CsrfConfigurerTests {
 		}
 	}
 
+	@Test
+	public void requireCsrfProtectionMatcherInLambdaWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
+		RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
+		this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
+		when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any()))
+				.thenReturn(false);
+
+		this.mvc.perform(get("/"))
+				.andExpect(status().isOk());
+	}
+
+	@Test
+	public void requireCsrfProtectionMatcherInLambdaWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
+		RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
+		when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any())).thenReturn(true);
+		this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
+
+		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);
@@ -454,6 +509,32 @@ 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 {
+		static CsrfTokenRepository REPO;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.csrf(csrf -> csrf.csrfTokenRepository(REPO));
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
 		AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);

+ 43 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -86,6 +86,48 @@ 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 {
+		AccessDeniedHandler teapotDeniedHandler =
+				(request, response, exception) ->
+						response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().denyAll()
+				)
+				.exceptionHandling(exceptionHandling ->
+					exceptionHandling
+						.defaultAccessDeniedHandlerFor(
+								this.teapotDeniedHandler,
+								new AntPathRequestMatcher("/hello/**")
+						)
+						.defaultAccessDeniedHandlerFor(
+								new AccessDeniedHandlerImpl(),
+								AnyRequestMatcher.INSTANCE
+						)
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	@WithMockUser(roles = "ANYTHING")
 	public void getWhenAccessDeniedOverriddenByOnlyOneHandlerThenAllRequestsUseThatHandler()

+ 150 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java

@@ -42,6 +42,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.logout;
 import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -195,6 +196,82 @@ public class FormLoginConfigurerTests {
 		}
 	}
 
+	@Test
+	public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
+		this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin().user("username", "user").password("password", "password"))
+				.andExpect(status().isFound())
+				.andExpect(redirectedUrl("/"));
+	}
+
+	@Test
+	public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception {
+		this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin().user("invalid"))
+				.andExpect(status().isFound())
+				.andExpect(redirectedUrl("/login?error"));
+	}
+
+	@Test
+	public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception {
+		this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin())
+				.andExpect(status().isFound())
+				.andExpect(redirectedUrl("/"));
+	}
+
+	@Test
+	public void getLoginPageWhenFormLoginDefaultsInLambdaThenNotSecured() throws Exception {
+		this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(get("/login"))
+				.andExpect(status().isOk());
+	}
+
+	@Test
+	public void loginWhenFormLoginDefaultsInLambdaThenSecured() throws Exception {
+		this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(post("/login"))
+				.andExpect(status().isForbidden());
+	}
+
+	@Test
+	public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception {
+		this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+		this.mockMvc.perform(get("/private"))
+				.andExpect(status().isFound())
+				.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();
@@ -297,6 +374,34 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.formLogin(formLogin ->
+					formLogin
+						.loginPage("/authenticate")
+						.permitAll()
+				)
+				.logout(LogoutConfigurer::permitAll);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
 		this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
@@ -340,6 +445,51 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.formLogin(formLogin ->
+					formLogin
+						.loginProcessingUrl("/loginCheck")
+						.loginPage("/login")
+						.defaultSuccessUrl("/", true)
+						.permitAll()
+				)
+				.logout(logout ->
+					logout
+						.logoutSuccessUrl("/login")
+						.logoutUrl("/logout")
+						.deleteCookies("JSESSIONID")
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void requestWhenCustomPortMapperThenPortMapperUsed() throws Exception {
 		FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);

+ 338 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java

@@ -36,6 +36,7 @@ import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
 
@@ -87,6 +88,36 @@ public class HeadersConfigurerTests {
 		}
 	}
 
+	@Test
+	public void getWhenHeadersConfiguredInLambdaThenDefaultHeadersInResponse() throws Exception {
+		this.spring.register(HeadersInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
+				.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.DENY.name()))
+				.andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains"))
+				.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
+				.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
+				.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
+				.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
+				HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
+				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 {
@@ -112,6 +143,33 @@ public class HeadersConfigurerTests {
 		}
 	}
 
+	@Test
+	public void getWhenOnlyContentTypeConfiguredInLambdaThenOnlyContentTypeHeaderInResponse()
+			throws Exception {
+		this.spring.register(ContentTypeOptionsInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/"))
+				.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
+				.andReturn();
+		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 {
@@ -190,6 +248,36 @@ public class HeadersConfigurerTests {
 		}
 	}
 
+	@Test
+	public void getWhenOnlyCacheControlConfiguredInLambdaThenCacheControlAndExpiresAndPragmaHeadersInResponse()
+			throws Exception {
+		this.spring.register(CacheControlInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
+				.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
+				.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
+				.andReturn();
+		assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(HttpHeaders.CACHE_CONTROL,
+				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 {
@@ -215,6 +303,33 @@ public class HeadersConfigurerTests {
 		}
 	}
 
+	@Test
+	public void getWhenOnlyXssProtectionConfiguredInLambdaThenOnlyXssProtectionHeaderInResponse()
+			throws Exception {
+		this.spring.register(XssProtectionInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
+				.andReturn();
+		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();
@@ -237,6 +352,31 @@ public class HeadersConfigurerTests {
 		}
 	}
 
+	@Test
+	public void getWhenFrameOptionsSameOriginConfiguredInLambdaThenFrameOptionsHeaderHasValueSameOrigin()
+			throws Exception {
+		this.spring.register(HeadersCustomSameOriginInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/").secure(true))
+				.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.SAMEORIGIN.name()))
+				.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();
@@ -465,6 +605,38 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.httpPublicKeyPinning(hpkp ->
+							hpkp
+								.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
+								.reportUri("https://example.net/pkp-report")
+						)
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
 		this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire();
@@ -515,6 +687,38 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.contentSecurityPolicy(csp ->
+							csp
+								.policyDirectives("default-src 'self'; script-src trustedscripts.example.com")
+								.reportOnly()
+						)
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void configureWhenContentSecurityPolicyEmptyThenException() {
 		assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidConfig.class).autowire())
@@ -536,6 +740,58 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.contentSecurityPolicy(csp ->
+								csp.policyDirectives("")
+						)
+				);
+			// @formatter:on
+		}
+	}
+
+	@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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.contentSecurityPolicy(withDefaults())
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
 		this.spring.register(ReferrerPolicyDefaultConfig.class).autowire();
@@ -560,6 +816,32 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.referrerPolicy()
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
 			throws Exception {
@@ -585,6 +867,34 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.referrerPolicy(referrerPolicy ->
+								referrerPolicy.policy(ReferrerPolicy.SAME_ORIGIN)
+						)
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
 		this.spring.register(FeaturePolicyConfig.class).autowire();
@@ -656,4 +966,32 @@ public class HeadersConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.headers(headers ->
+					headers
+						.defaultsDisabled()
+						.httpStrictTransportSecurity(hstsConfig -> hstsConfig.preload(true))
+				);
+			// @formatter:on
+		}
+	}
 }

+ 4 - 3
config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java

@@ -107,9 +107,10 @@ public class HttpBasicConfigurerTests {
 		protected void configure(HttpSecurity http) throws Exception {
 			// @formatter:off
 			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
 				.httpBasic(withDefaults());
 			// @formatter:on
 		}

+ 118 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.security.config.Customizer.withDefaults;
 
 /**
  * @author Rob Winch
@@ -195,6 +196,62 @@ public class HttpSecurityRequestMatchersTests {
 		}
 	}
 
+	@Test
+	public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception {
+		loadConfig(RequestMatchersMvcMatcherInLambdaConfig.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
+	static class RequestMatchersMvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requestMatchers(requestMatchers ->
+					requestMatchers
+						.mvcMatchers("/path")
+				)
+				.httpBasic(withDefaults())
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().denyAll()
+				);
+			// @formatter:on
+		}
+
+		@RestController
+		static class PathController {
+			@RequestMapping("/path")
+			public String path() {
+				return "path";
+			}
+		}
+	}
+
 	@Test
 	public void requestMatchersMvcMatcherServletPath() throws Exception {
 		loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
@@ -260,6 +317,66 @@ 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
+	static class RequestMatchersMvcMatcherServletPathInLambdaConfig
+			extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requestMatchers(requestMatchers ->
+					requestMatchers
+						.mvcMatchers("/path").servletPath("/spring")
+						.mvcMatchers("/never-match")
+				)
+				.httpBasic(withDefaults())
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().denyAll()
+				);
+			// @formatter:on
+		}
+
+		@RestController
+		static class PathController {
+			@RequestMapping("/path")
+			public String path() {
+				return "path";
+			}
+		}
+	}
+
 	public void loadConfig(Class<?>... configs) {
 		this.context = new AnnotationConfigWebApplicationContext();
 		this.context.register(configs);

+ 114 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java

@@ -25,6 +25,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
+import org.springframework.security.core.userdetails.User;
 import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
 import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
 import org.springframework.test.web.servlet.MockMvc;
@@ -125,4 +128,115 @@ public class JeeConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.jee(jee ->
+					jee
+						.mappableRoles("USER")
+				);
+			// @formatter:on
+		}
+	}
+
+	@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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.jee(jee ->
+					jee
+						.mappableAuthorities("ROLE_USER")
+				);
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		static AuthenticationUserDetailsService authenticationUserDetailsService =
+				mock(AuthenticationUserDetailsService.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.jee(jee ->
+					jee
+						.authenticatedUserDetailsService(authenticationUserDetailsService)
+				);
+			// @formatter:on
+		}
+	}
 }

+ 88 - 2
config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java

@@ -37,10 +37,15 @@ import org.springframework.test.web.servlet.MockMvc;
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
@@ -77,6 +82,26 @@ public class LogoutConfigurerTests {
 		}
 	}
 
+	@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())
@@ -96,6 +121,26 @@ public class LogoutConfigurerTests {
 		}
 	}
 
+	@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();
@@ -263,6 +308,29 @@ public class LogoutConfigurerTests {
 		}
 	}
 
+	@Test
+	public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
+		this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire();
+
+		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() {
@@ -283,6 +351,24 @@ public class LogoutConfigurerTests {
 		}
 	}
 
+	@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 {

+ 12 - 9
config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java

@@ -125,9 +125,10 @@ public class NamespaceHttpBasicTests {
 		protected void configure(HttpSecurity http) throws Exception {
 			// @formatter:off
 			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
 				.httpBasic(withDefaults());
 			// @formatter:on
 		}
@@ -174,9 +175,10 @@ public class NamespaceHttpBasicTests {
 		protected void configure(HttpSecurity http) throws Exception {
 			// @formatter:off
 			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
 				.httpBasic(httpBasicConfig -> httpBasicConfig.realmName("Custom Realm"));
 			// @formatter:on
 		}
@@ -310,9 +312,10 @@ public class NamespaceHttpBasicTests {
 		protected void configure(HttpSecurity http) throws Exception {
 			// @formatter:off
 			http
-				.authorizeRequests()
-					.anyRequest().hasRole("USER")
-					.and()
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
 				.httpBasic(httpBasicConfig ->
 						httpBasicConfig.authenticationEntryPoint(this.authenticationEntryPoint));
 			// @formatter:on

+ 74 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java

@@ -41,9 +41,11 @@ import org.springframework.test.web.servlet.ResultMatcher;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 /**
  * Tests to verify that all the functionality of <logout> attributes is present
@@ -83,6 +85,23 @@ public class NamespaceHttpLogoutTests {
 		}
 	}
 
+	@Test
+	@WithMockUser
+	public void logoutWhenDisabledInLambdaThenRespondsWithNotFound() throws Exception {
+		this.spring.register(HttpLogoutDisabledInLambdaConfig.class).autowire();
+
+		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
 	 */
@@ -112,6 +131,35 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.logout(logout ->
+						logout.deleteCookies("remove")
+							.invalidateHttpSession(false)
+							.logoutUrl("/custom-logout")
+							.logoutSuccessUrl("/logout-success")
+				);
+			// @formatter:on
+		}
+	}
+
 	/**
 	 * http/logout@success-handler-ref
 	 */
@@ -141,6 +189,32 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
+			logoutSuccessHandler.setDefaultTargetUrl("/SuccessHandlerRefHttpLogoutConfig");
+
+			// @formatter:off
+			http
+				.logout(logout -> logout.logoutSuccessHandler(logoutSuccessHandler));
+			// @formatter:on
+		}
+	}
+
 	ResultMatcher authenticated(boolean authenticated) {
 		return result -> assertThat(
 				Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())

+ 60 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java

@@ -83,6 +83,32 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
 		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 {
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().denyAll()
+				)
+				.exceptionHandling(exceptionHandling ->
+					exceptionHandling.accessDeniedPage("/AccessDeniedPageConfig")
+				);
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void requestWhenCustomAccessDeniedHandlerThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(AccessDeniedHandlerRefConfig.class).autowire();
@@ -109,6 +135,40 @@ 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 {
+		static AccessDeniedHandler accessDeniedHandler = mock(AccessDeniedHandler.class);
+
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().denyAll()
+				)
+				.exceptionHandling(exceptionHandling ->
+						exceptionHandling.accessDeniedHandler(accessDeniedHandler())
+				);
+			// @formatter:on
+		}
+
+		@Bean
+		AccessDeniedHandler accessDeniedHandler() {
+			return accessDeniedHandler;
+		}
+	}
+
 	private <T> T verifyBean(Class<T> beanClass) {
 		return verify(this.spring.getContext().getBean(beanClass));
 	}

+ 58 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,8 +22,11 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.web.PortMapperImpl;
 import org.springframework.test.web.servlet.MockMvc;
 
+import java.util.Collections;
+
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
 
@@ -61,4 +64,58 @@ public class PortMapperConfigurerTests {
 				.portMapper();
 		}
 	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requiresChannel(requiresChannel ->
+					requiresChannel
+					.anyRequest().requiresSecure()
+				)
+				.portMapper(portMapper ->
+					portMapper
+						.http(543).mapsTo(123)
+				);
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			PortMapperImpl customPortMapper = new PortMapperImpl();
+			customPortMapper.setPortMappings(Collections.singletonMap("543", "123"));
+			// @formatter:off
+			http
+				.requiresChannel(requiresChannel ->
+					requiresChannel
+						.anyRequest().requiresSecure()
+				)
+				.portMapper(portMapper ->
+					portMapper
+						.portMapper(customPortMapper)
+				);
+			// @formatter:on
+		}
+	}
 }

+ 80 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java

@@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
 import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -299,6 +300,45 @@ 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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.formLogin(withDefaults())
+				.rememberMe(withDefaults());
+			// @formatter:on
+		}
+
+		@Autowired
+		public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception {
 		this.spring.register(RememberMeCookieDomainConfig.class).autowire();
@@ -337,6 +377,46 @@ 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 {
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().hasRole("USER")
+				)
+				.formLogin(withDefaults())
+				.rememberMe(rememberMe ->
+					rememberMe
+						.rememberMeCookieDomain("spring.io")
+				);
+			// @formatter:on
+		}
+
+		@Autowired
+		public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
 	@Test
 	public void configureWhenRememberMeCookieNameAndRememberMeServicesThenException() {
 		assertThatThrownBy(() -> this.spring.register(RememberMeCookieNameAndRememberMeServicesConfig.class).autowire())

+ 90 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
 import org.springframework.security.config.test.SpringTestRule;
 import org.springframework.security.core.userdetails.User;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.savedrequest.NullRequestCache;
 import org.springframework.security.web.savedrequest.RequestCache;
 import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
 import org.springframework.test.web.servlet.MockMvc;
@@ -42,6 +43,7 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -271,6 +273,93 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.formLogin(withDefaults())
+				.requestCache(RequestCacheConfigurer::disable);
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.formLogin(withDefaults())
+				.requestCache(withDefaults());
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.formLogin(withDefaults())
+				.requestCache(requestCache ->
+					requestCache
+						.requestCache(new NullRequestCache())
+				);
+			// @formatter:on
+		}
+	}
+
 	@EnableWebSecurity
 	static class DefaultSecurityConfig {
 

+ 33 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java

@@ -71,4 +71,37 @@ public class RequestMatcherConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@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 {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.requestMatchers(requestMatchers ->
+					requestMatchers
+						.antMatchers("/api/**")
+				)
+				.requestMatchers(requestMatchers ->
+					requestMatchers
+						.antMatchers("/oauth/**")
+				)
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().denyAll()
+				);
+			// @formatter:on
+		}
+	}
 }

+ 101 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java

@@ -28,14 +28,22 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
 import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.userdetails.PasswordEncodedUser;
 import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.security.web.context.NullSecurityContextRepository;
 import org.springframework.security.web.context.SecurityContextPersistenceFilter;
 import org.springframework.security.web.context.SecurityContextRepository;
 import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
 import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
 
+import javax.servlet.http.HttpSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.*;
+import static org.springframework.security.config.Customizer.withDefaults;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 
 /**
@@ -151,4 +159,97 @@ public class SecurityContextConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.securityContext(withDefaults());
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.securityContext(AbstractHttpConfigurer::disable);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.securityContext(securityContext ->
+					securityContext
+						.securityContextRepository(new NullSecurityContextRepository())
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
 }

+ 48 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java

@@ -47,6 +47,7 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
@@ -230,6 +231,53 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.servletApi(withDefaults());
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.servletApi(servletApi ->
+					servletApi
+						.rolePrefix("PERMISSION_")
+				);
+			// @formatter:on
+		}
+	}
+
 	@RestController
 	static class AdminController {
 		@GetMapping("/admin")

+ 116 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java

@@ -54,6 +54,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -201,6 +202,51 @@ public class SessionManagementConfigurerTests {
 		}
 	}
 
+	@Test
+	public void authenticateWhenNewSessionFixationProtectionInLambdaThenCreatesNewSession() throws Exception {
+		this.spring.register(SFPNewSessionInLambdaConfig.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 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();
@@ -262,6 +308,76 @@ public class SessionManagementConfigurerTests {
 		}
 	}
 
+	@Test
+	public void loginWhenUserLoggedInAndMaxSessionsOneInLambdaThenLoginPrevented() throws Exception {
+		this.spring.register(ConcurrencyControlInLambdaConfig.class).autowire();
+
+		this.mvc.perform(post("/login")
+				.with(csrf())
+				.param("username", "user")
+				.param("password", "password"));
+
+		this.mvc.perform(post("/login")
+				.with(csrf())
+				.param("username", "user")
+				.param("password", "password"))
+				.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();
+
+		MvcResult mvcResult = this.mvc.perform(get("/"))
+				.andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+
+		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);

+ 64 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java

@@ -38,6 +38,7 @@ import java.security.cert.X509Certificate;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509;
 import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -122,6 +123,69 @@ 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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.x509(withDefaults());
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser("rod").password("password").roles("USER", "ADMIN");
+			// @formatter:on
+		}
+	}
+
+	@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 {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.x509(x509 ->
+					x509
+						.subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)")
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser("rod").password("password").roles("USER", "ADMIN");
+			// @formatter:on
+		}
+	}
+
 	private <T extends Certificate> T loadCert(String location) {
 		try (InputStream is = new ClassPathResource(location).getInputStream()) {
 			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

+ 40 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java

@@ -65,6 +65,7 @@ import java.util.Map;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.*;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -141,6 +142,19 @@ public class OAuth2ClientConfigurerTests {
 				"redirect_uri=http://localhost/client-1");
 	}
 
+	@Test
+	public void configureWhenOauth2ClientInLambdaThenRedirectForAuthorization() throws Exception {
+		this.spring.register(OAuth2ClientInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
+			.andExpect(status().is3xxRedirection())
+			.andReturn();
+		assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://provider.com/oauth2/authorize\\?" +
+				"response_type=code&client_id=client-1&" +
+				"scope=user&state=.{15,}&" +
+				"redirect_uri=http://localhost/client-1");
+	}
+
 	@Test
 	public void configureWhenAuthorizationCodeResponseSuccessThenAuthorizedClientSaved() throws Exception {
 		this.spring.register(OAuth2ClientConfig.class).autowire();
@@ -248,4 +262,30 @@ public class OAuth2ClientConfigurerTests {
 			}
 		}
 	}
+
+	@EnableWebSecurity
+	@EnableWebMvc
+	static class OAuth2ClientInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.oauth2Client(withDefaults());
+			// @formatter:on
+		}
+
+		@Bean
+		public ClientRegistrationRepository clientRegistrationRepository() {
+			return clientRegistrationRepository;
+		}
+
+		@Bean
+		public OAuth2AuthorizedClientRepository authorizedClientRepository() {
+			return authorizedClientRepository;
+		}
+	}
 }

+ 183 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java

@@ -176,6 +176,25 @@ public class OAuth2LoginConfigurerTests {
 				.isInstanceOf(OAuth2UserAuthority.class).hasToString("ROLE_USER");
 	}
 
+	@Test
+	public void requestWhenOauth2LoginInLambdaThenAuthenticationContainsOauth2UserAuthority() throws Exception {
+		loadConfig(OAuth2LoginInLambdaConfig.class);
+		OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest();
+		this.authorizationRequestRepository.saveAuthorizationRequest(
+			authorizationRequest, this.request, this.response);
+		this.request.setParameter("code", "code123");
+		this.request.setParameter("state", authorizationRequest.getState());
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+		Authentication authentication = this.securityContextRepository
+				.loadContext(new HttpRequestResponseHolder(this.request, this.response))
+				.getAuthentication();
+		assertThat(authentication.getAuthorities()).hasSize(1);
+		assertThat(authentication.getAuthorities()).first()
+				.isInstanceOf(OAuth2UserAuthority.class).hasToString("ROLE_USER");
+	}
+
 	// gh-6009
 	@Test
 	public void oauth2LoginWhenSuccessThenAuthenticationSuccessEventPublished() throws Exception {
@@ -303,6 +322,29 @@ public class OAuth2LoginConfigurerTests {
 		assertThat(this.response.getRedirectedUrl()).isEqualTo("https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1");
 	}
 
+	@Test
+	public void requestWhenOauth2LoginWithCustomAuthorizationRequestParametersThenParametersInRedirectedUrl()
+			throws Exception {
+		loadConfig(OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda.class);
+		OAuth2AuthorizationRequestResolver resolver = this.context.getBean(
+				OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda.class).resolver;
+		OAuth2AuthorizationRequest result = OAuth2AuthorizationRequest.authorizationCode()
+				.authorizationUri("https://accounts.google.com/authorize")
+				.clientId("client-id")
+				.state("adsfa")
+				.authorizationRequestUri("https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1")
+				.build();
+		when(resolver.resolve(any())).thenReturn(result);
+
+		String requestUri = "/oauth2/authorization/google";
+		this.request = new MockHttpServletRequest("GET", requestUri);
+		this.request.setServletPath(requestUri);
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+		assertThat(this.response.getRedirectedUrl()).isEqualTo("https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1");
+	}
+
 	// gh-5347
 	@Test
 	public void oauth2LoginWithOneClientConfiguredThenRedirectForAuthorization() throws Exception {
@@ -374,6 +416,19 @@ public class OAuth2LoginConfigurerTests {
 		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/custom-login");
 	}
 
+	@Test
+	public void requestWhenOauth2LoginWithCustomLoginPageInLambdaThenRedirectCustomLoginPage() throws Exception {
+		loadConfig(OAuth2LoginConfigCustomLoginPageInLambda.class);
+
+		String requestUri = "/";
+		this.request = new MockHttpServletRequest("GET", requestUri);
+		this.request.setServletPath(requestUri);
+
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/custom-login");
+	}
+
 	@Test
 	public void oidcLogin() throws Exception {
 		// setup application context
@@ -400,6 +455,32 @@ public class OAuth2LoginConfigurerTests {
 				.isInstanceOf(OidcUserAuthority.class).hasToString("ROLE_USER");
 	}
 
+	@Test
+	public void requestWhenOauth2LoginInLambdaAndOidcThenAuthenticationContainsOidcUserAuthority() throws Exception {
+		// setup application context
+		loadConfig(OAuth2LoginInLambdaConfig.class, JwtDecoderFactoryConfig.class);
+
+		// setup authorization request
+		OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest("openid");
+		this.authorizationRequestRepository.saveAuthorizationRequest(
+			authorizationRequest, this.request, this.response);
+
+		// setup authentication parameters
+		this.request.setParameter("code", "code123");
+		this.request.setParameter("state", authorizationRequest.getState());
+
+		// perform test
+		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+		// assertions
+		Authentication authentication = this.securityContextRepository
+				.loadContext(new HttpRequestResponseHolder(this.request, this.response))
+				.getAuthentication();
+		assertThat(authentication.getAuthorities()).hasSize(1);
+		assertThat(authentication.getAuthorities()).first()
+				.isInstanceOf(OidcUserAuthority.class).hasToString("ROLE_USER");
+	}
+
 	@Test
 	public void oidcLoginCustomWithConfigurer() throws Exception {
 		// setup application context
@@ -521,6 +602,30 @@ public class OAuth2LoginConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class OAuth2LoginInLambdaConfig extends CommonLambdaWebSecurityConfigurerAdapter
+			implements ApplicationListener<AuthenticationSuccessEvent> {
+		static List<AuthenticationSuccessEvent> EVENTS = new ArrayList<>();
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.oauth2Login(oauth2Login ->
+					oauth2Login
+						.clientRegistrationRepository(
+							new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
+				);
+			// @formatter:on
+			super.configure(http);
+		}
+
+		@Override
+		public void onApplicationEvent(AuthenticationSuccessEvent event) {
+			EVENTS.add(event);
+		}
+	}
+
 	@EnableWebSecurity
 	static class OAuth2LoginConfigCustomWithConfigurer extends CommonWebSecurityConfigurerAdapter {
 		@Override
@@ -586,6 +691,28 @@ public class OAuth2LoginConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda extends CommonLambdaWebSecurityConfigurerAdapter {
+		private ClientRegistrationRepository clientRegistrationRepository =
+				new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION);
+
+		OAuth2AuthorizationRequestResolver resolver = mock(OAuth2AuthorizationRequestResolver.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			http
+				.oauth2Login(oauth2Login ->
+					oauth2Login
+						.clientRegistrationRepository(this.clientRegistrationRepository)
+						.authorizationEndpoint(authorizationEndpoint ->
+							authorizationEndpoint
+								.authorizationRequestResolver(this.resolver)
+						)
+				);
+			super.configure(http);
+		}
+	}
+
 	@EnableWebSecurity
 	static class OAuth2LoginConfigMultipleClients extends CommonWebSecurityConfigurerAdapter {
 		@Override
@@ -612,6 +739,23 @@ public class OAuth2LoginConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class OAuth2LoginConfigCustomLoginPageInLambda extends CommonLambdaWebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.oauth2Login(oauth2Login ->
+						oauth2Login
+							.clientRegistrationRepository(
+									new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
+							.loginPage("/custom-login")
+				);
+			// @formatter:on
+			super.configure(http);
+		}
+	}
+
 	@EnableWebSecurity
 	static class OAuth2LoginConfigWithOidcLogoutSuccessHandler extends CommonWebSecurityConfigurerAdapter {
 		@Override
@@ -667,6 +811,45 @@ public class OAuth2LoginConfigurerTests {
 		}
 	}
 
+	private static abstract class CommonLambdaWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.securityContext(securityContext ->
+					securityContext
+						.securityContextRepository(securityContextRepository())
+				)
+				.oauth2Login(oauth2Login ->
+					oauth2Login
+						.tokenEndpoint(tokenEndpoint ->
+							tokenEndpoint
+								.accessTokenResponseClient(createOauth2AccessTokenResponseClient())
+						)
+						.userInfoEndpoint(userInfoEndpoint ->
+							userInfoEndpoint
+								.userService(createOauth2UserService())
+								.oidcUserService(createOidcUserService())
+						)
+				);
+			// @formatter:on
+		}
+
+		@Bean
+		SecurityContextRepository securityContextRepository() {
+			return new HttpSessionSecurityContextRepository();
+		}
+
+		@Bean
+		HttpSessionOAuth2AuthorizationRequestRepository oauth2AuthorizationRequestRepository() {
+			return new HttpSessionOAuth2AuthorizationRequestRepository();
+		}
+	}
+
 	@Configuration
 	static class JwtDecoderFactoryConfig {
 

+ 183 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

@@ -127,6 +127,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.oauth2.core.TestOAuth2AccessTokens.noScopes;
 import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri;
 import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withPublicKey;
@@ -184,6 +185,19 @@ public class OAuth2ResourceServerConfigurerTests {
 				.andExpect(content().string("ok"));
 	}
 
+	@Test
+	public void getWhenUsingDefaultsInLambdaWithValidBearerTokenThenAcceptsRequest()
+			throws Exception {
+
+		this.spring.register(RestOperationsConfig.class, DefaultInLambdaConfig.class, BasicController.class).autowire();
+		mockRestOperations(jwks("Default"));
+		String token = this.token("ValidNoScopes");
+
+		this.mvc.perform(get("/").with(bearerToken(token)))
+				.andExpect(status().isOk())
+				.andExpect(content().string("ok"));
+	}
+
 	@Test
 	public void getWhenUsingJwkSetUriThenAcceptsRequest() throws Exception {
 		this.spring.register(WebServerConfig.class, JwkSetUriConfig.class, BasicController.class).autowire();
@@ -195,6 +209,16 @@ public class OAuth2ResourceServerConfigurerTests {
 				.andExpect(content().string("ok"));
 	}
 
+	@Test
+	public void getWhenUsingJwkSetUriInLambdaThenAcceptsRequest() throws Exception {
+		this.spring.register(WebServerConfig.class, JwkSetUriInLambdaConfig.class, BasicController.class).autowire();
+		mockWebServer(jwks("Default"));
+		String token = this.token("ValidNoScopes");
+
+		this.mvc.perform(get("/").with(bearerToken(token)))
+				.andExpect(status().isOk())
+				.andExpect(content().string("ok"));
+	}
 
 	@Test
 	public void getWhenUsingDefaultsWithExpiredBearerTokenThenInvalidToken()
@@ -756,6 +780,23 @@ public class OAuth2ResourceServerConfigurerTests {
 				.andExpect(content().string(JWT_SUBJECT));
 	}
 
+	@Test
+	public void requestWhenCustomJwtDecoderInLambdaOnDslThenUsed()
+			throws Exception {
+
+		this.spring.register(CustomJwtDecoderInLambdaOnDsl.class, BasicController.class).autowire();
+
+		CustomJwtDecoderInLambdaOnDsl config = this.spring.getContext().getBean(CustomJwtDecoderInLambdaOnDsl.class);
+		JwtDecoder decoder = config.decoder();
+
+		when(decoder.decode(anyString())).thenReturn(JWT);
+
+		this.mvc.perform(get("/authenticated")
+				.with(bearerToken(JWT_TOKEN)))
+				.andExpect(status().isOk())
+				.andExpect(content().string(JWT_SUBJECT));
+	}
+
 	@Test
 	public void requestWhenCustomJwtDecoderExposedAsBeanThenUsed()
 			throws Exception {
@@ -1067,6 +1108,17 @@ public class OAuth2ResourceServerConfigurerTests {
 				.andExpect(content().string("test-subject"));
 	}
 
+	@Test
+	public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception {
+		this.spring.register(RestOperationsConfig.class, OpaqueTokenInLambdaConfig.class, BasicController.class).autowire();
+		mockRestOperations(json("Active"));
+
+		this.mvc.perform(get("/authenticated")
+				.with(bearerToken("token")))
+				.andExpect(status().isOk())
+				.andExpect(content().string("test-subject"));
+	}
+
 	@Test
 	public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
 		this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
@@ -1104,6 +1156,20 @@ public class OAuth2ResourceServerConfigurerTests {
 		verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
 	}
 
+	@Test
+	public void getWhenCustomIntrospectionAuthenticationManagerInLambdaThenUsed() throws Exception {
+		this.spring.register(OpaqueTokenAuthenticationManagerInLambdaConfig.class, BasicController.class).autowire();
+
+		when(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
+				.thenReturn(INTROSPECTION_AUTHENTICATION_TOKEN);
+		this.mvc.perform(get("/authenticated")
+				.with(bearerToken("token")))
+				.andExpect(status().isOk())
+				.andExpect(content().string("mock-test-subject"));
+
+		verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
+	}
+
 	@Test
 	public void configureWhenOnlyIntrospectionUrlThenException() throws Exception {
 		assertThatCode(() -> this.spring.register(OpaqueTokenHalfConfiguredConfig.class).autowire())
@@ -1311,6 +1377,26 @@ public class OAuth2ResourceServerConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class DefaultInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.antMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')")
+						.anyRequest().authenticated()
+				)
+				.oauth2ResourceServer(oauth2ResourceServer ->
+					oauth2ResourceServer
+						.jwt(withDefaults())
+				);
+			// @formatter:on
+		}
+	}
+
 	@EnableWebSecurity
 	static class JwkSetUriConfig extends WebSecurityConfigurerAdapter {
 		@Value("${mockwebserver.url:https://example.org}")
@@ -1331,6 +1417,31 @@ public class OAuth2ResourceServerConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class JwkSetUriInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Value("${mockwebserver.url:https://example.org}")
+		String jwkSetUri;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.antMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')")
+						.anyRequest().authenticated()
+				)
+				.oauth2ResourceServer(oauth2ResourceServer ->
+					oauth2ResourceServer
+						.jwt(jwt ->
+							jwt
+								.jwkSetUri(this.jwkSetUri)
+						)
+				);
+			// @formatter:on
+		}
+	}
+
 	@EnableWebSecurity
 	static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
 		@Value("${mockwebserver.url:https://example.org}")
@@ -1677,6 +1788,33 @@ public class OAuth2ResourceServerConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class CustomJwtDecoderInLambdaOnDsl extends WebSecurityConfigurerAdapter {
+		JwtDecoder decoder = mock(JwtDecoder.class);
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.oauth2ResourceServer(oauth2ResourceServer ->
+					oauth2ResourceServer
+						.jwt(jwt ->
+							jwt
+								.decoder(decoder())
+						)
+				);
+			// @formatter:on
+		}
+
+		JwtDecoder decoder() {
+			return this.decoder;
+		}
+	}
+
 	@EnableWebSecurity
 	static class CustomJwtDecoderAsBean extends WebSecurityConfigurerAdapter {
 		@Override
@@ -1831,6 +1969,25 @@ public class OAuth2ResourceServerConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class OpaqueTokenInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.antMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read")
+						.anyRequest().authenticated()
+				)
+				.oauth2ResourceServer(oauth2ResourceServer ->
+					oauth2ResourceServer
+						.opaqueToken(withDefaults())
+				);
+			// @formatter:on
+		}
+	}
+
 	@EnableWebSecurity
 	static class OpaqueTokenAuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
 		@Override
@@ -1852,6 +2009,32 @@ public class OAuth2ResourceServerConfigurerTests {
 		}
 	}
 
+	@EnableWebSecurity
+	static class OpaqueTokenAuthenticationManagerInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.oauth2ResourceServer(oauth2ResourceServer ->
+					oauth2ResourceServer
+						.opaqueToken(opaqueToken ->
+							opaqueToken
+								.authenticationManager(authenticationProvider()::authenticate)
+						)
+				);
+			// @formatter:on
+		}
+
+		@Bean
+		public AuthenticationProvider authenticationProvider() {
+			return mock(AuthenticationProvider.class);
+		}
+	}
+
 	@EnableWebSecurity
 	static class OpaqueAndJwtConfig extends WebSecurityConfigurerAdapter {
 		@Override

+ 178 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java

@@ -16,8 +16,13 @@
 
 package org.springframework.security.config.annotation.web.configurers.openid;
 
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
 import org.junit.Rule;
 import org.junit.Test;
+import org.openid4java.consumer.ConsumerManager;
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.security.config.annotation.ObjectPostProcessor;
@@ -26,13 +31,23 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.openid.OpenIDAttribute;
 import org.springframework.security.openid.OpenIDAuthenticationFilter;
 import org.springframework.security.openid.OpenIDAuthenticationProvider;
 import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
 
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.openid4java.discovery.yadis.YadisResolver.YADIS_XRDS_LOCATION;
+import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -128,4 +143,167 @@ public class OpenIDLoginConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@Test
+	public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception {
+		this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire();
+
+		this.mvc.perform(get("/"))
+				.andExpect(status().isFound())
+				.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);
+		AuthRequest mockAuthRequest = mock(AuthRequest.class);
+		DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
+		when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl");
+		when(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.associate(any()))
+				.thenReturn(mockDiscoveryInformation);
+		when(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(), any()))
+				.thenReturn(mockAuthRequest);
+		this.spring.register(OpenIdAttributesInLambdaConfig.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("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", 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<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
+			assertThat(attributeList.stream().anyMatch(attribute ->
+					"nickname".equals(attribute.getName())
+							&& "https://schema.openid.net/namePerson/friendly".equals(attribute.getType())))
+					.isTrue();
+			assertThat(attributeList.stream().anyMatch(attribute ->
+					"email".equals(attribute.getName())
+							&& "https://schema.openid.net/contact/email".equals(attribute.getType())
+							&& attribute.isRequired()
+							&& attribute.getCount() == 2))
+					.isTrue();
+		}
+	}
+
+	@EnableWebSecurity
+	static class OpenIdAttributesInLambdaConfig extends WebSecurityConfigurerAdapter {
+		static ConsumerManager CONSUMER_MANAGER;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().permitAll()
+				)
+				.openidLogin(openIdLogin ->
+					openIdLogin
+						.consumerManager(CONSUMER_MANAGER)
+						.attributeExchange(attributeExchange ->
+								attributeExchange
+									.identifierPattern(".*")
+									.attribute(nicknameAttribute ->
+										nicknameAttribute
+											.name("nickname")
+											.type("https://schema.openid.net/namePerson/friendly")
+									)
+									.attribute(emailAttribute ->
+										emailAttribute
+											.name("email")
+											.type("https://schema.openid.net/contact/email")
+											.required(true)
+											.count(2)
+									)
+						)
+				);
+			// @formatter:on
+		}
+	}
+
+	@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("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", 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<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
+			assertThat(attributeList).hasSize(1);
+			assertThat(attributeList.get(0).getName()).isEqualTo("default-attribute");
+		}
+	}
+
+	@EnableWebSecurity
+	static class OpenIdAttributesNullNameConfig extends WebSecurityConfigurerAdapter {
+		static ConsumerManager CONSUMER_MANAGER;
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().permitAll()
+				)
+				.openidLogin(openIdLogin ->
+					openIdLogin
+							.consumerManager(CONSUMER_MANAGER)
+						.attributeExchange(attributeExchange ->
+								attributeExchange
+									.identifierPattern(".*")
+									.attribute(withDefaults())
+						)
+				);
+			// @formatter:on
+		}
+	}
 }

+ 8 - 4
docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/mvc.adoc

@@ -104,8 +104,10 @@ If we wanted to restrict access to this controller method to admin users, a deve
 ----
 protected configure(HttpSecurity http) throws Exception {
 	http
-		.authorizeRequests()
-			.antMatchers("/admin").hasRole("ADMIN");
+		.authorizeRequests(authorizeRequests ->
+		    authorizeRequests
+			    .antMatchers("/admin").hasRole("ADMIN")
+		);
 }
 ----
 
@@ -133,8 +135,10 @@ The following configuration will protect the same URLs that Spring MVC will matc
 ----
 protected configure(HttpSecurity http) throws Exception {
 	http
-		.authorizeRequests()
-			.mvcMatchers("/admin").hasRole("ADMIN");
+		.authorizeRequests(authorizeRequests ->
+		    authorizeRequests
+			    .mvcMatchers("/admin").hasRole("ADMIN")
+		);
 }
 ----
 

+ 107 - 61
docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/oauth2.adoc

@@ -16,15 +16,25 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.authorizationEndpoint()
-					...
-				.redirectionEndpoint()
-					...
-				.tokenEndpoint()
-					...
-				.userInfoEndpoint()
-					...
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .authorizationEndpoint(authorizationEndpoint ->
+			            authorizationEndpoint
+			                ...
+			        )
+			        .redirectionEndpoint(redirectionEndpoint ->
+			            redirectionEndpoint
+			                ...
+			        )
+			        .tokenEndpoint(tokenEndpoint ->
+			            tokenEndpoint
+			                ...
+			        )
+			        .userInfoEndpoint(userInfoEndpoint ->
+			            userInfoEndpoint
+			                ...
+			        )
+			);
 	}
 }
 ----
@@ -58,27 +68,34 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.clientRegistrationRepository(this.clientRegistrationRepository())
-				.authorizedClientRepository(this.authorizedClientRepository())
-				.authorizedClientService(this.authorizedClientService())
-				.loginPage("/login")
-				.authorizationEndpoint()
-					.baseUri(this.authorizationRequestBaseUri())
-					.authorizationRequestRepository(this.authorizationRequestRepository())
-					.authorizationRequestResolver(this.authorizationRequestResolver())
-					.and()
-				.redirectionEndpoint()
-					.baseUri(this.authorizationResponseBaseUri())
-					.and()
-				.tokenEndpoint()
-					.accessTokenResponseClient(this.accessTokenResponseClient())
-					.and()
-				.userInfoEndpoint()
-					.userAuthoritiesMapper(this.userAuthoritiesMapper())
-					.userService(this.oauth2UserService())
-					.oidcUserService(this.oidcUserService())
-					.customUserType(GitHubOAuth2User.class, "github");
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .clientRegistrationRepository(this.clientRegistrationRepository())
+			        .authorizedClientRepository(this.authorizedClientRepository())
+			        .authorizedClientService(this.authorizedClientService())
+			        .loginPage("/login")
+			        .authorizationEndpoint(authorizationEndpoint ->
+			            authorizationEndpoint
+			                .baseUri(this.authorizationRequestBaseUri())
+			                .authorizationRequestRepository(this.authorizationRequestRepository())
+			                .authorizationRequestResolver(this.authorizationRequestResolver())
+			        )
+			        .redirectionEndpoint(redirectionEndpoint ->
+			             redirectionEndpoint
+			                .baseUri(this.authorizationResponseBaseUri())
+			        )
+			        .tokenEndpoint(tokenEndpoint ->
+			            tokenEndpoint
+			                .accessTokenResponseClient(this.accessTokenResponseClient())
+			        )
+			        .userInfoEndpoint(userInfoEndpoint ->
+			            userInfoEndpoint
+			                .userAuthoritiesMapper(this.userAuthoritiesMapper())
+			                .userService(this.oauth2UserService())
+			                .oidcUserService(this.oidcUserService())
+			                .customUserType(GitHubOAuth2User.class, "github")
+			        )
+			);
 	}
 }
 ----
@@ -123,12 +140,16 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.loginPage("/login/oauth2")
-				...
-				.authorizationEndpoint()
-					.baseUri("/login/oauth2/authorization")
-					....
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .loginPage("/login/oauth2")
+			        ...
+			        .authorizationEndpoint(authorizationEndpoint ->
+			            authorizationEndpoint
+			                .baseUri("/login/oauth2/authorization")
+			                ...
+			        )
+			);
 	}
 }
 ----
@@ -171,10 +192,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.redirectionEndpoint()
-					.baseUri("/login/oauth2/callback/*")
-					....
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .redirectionEndpoint(redirectionEndpoint ->
+			            redirectionEndpoint
+			                .baseUri("/login/oauth2/callback/*")
+			                ...
+			        )
+			);
 	}
 }
 ----
@@ -234,10 +259,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.userInfoEndpoint()
-					.userAuthoritiesMapper(this.userAuthoritiesMapper())
-					...
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .userInfoEndpoint(userInfoEndpoint ->
+			            userInfoEndpoint
+			                .userAuthoritiesMapper(this.userAuthoritiesMapper())
+			                ...
+			        )
+			);
 	}
 
 	private GrantedAuthoritiesMapper userAuthoritiesMapper() {
@@ -280,7 +309,8 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
-		http.oauth2Login();
+		http
+		    .oauth2Login(withDefaults());
 	}
 
 	@Bean
@@ -308,10 +338,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.userInfoEndpoint()
-					.oidcUserService(this.oidcUserService())
-					...
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .userInfoEndpoint(userInfoEndpoint ->
+			            userInfoEndpoint
+			                .oidcUserService(this.oidcUserService())
+			                ...
+			        )
+			);
 	}
 
 	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
@@ -355,10 +389,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.userInfoEndpoint()
-					.customUserType(GitHubOAuth2User.class, "github")
-					...
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .userInfoEndpoint(userInfoEndpoint ->
+			            userInfoEndpoint
+			                .customUserType(GitHubOAuth2User.class, "github")
+			                ...
+			        )
+			);
 	}
 }
 ----
@@ -469,10 +507,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.userInfoEndpoint()
-					.userService(this.oauth2UserService())
-					...
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+			        .userInfoEndpoint(userInfoEndpoint ->
+			            userInfoEndpoint
+			                .userService(this.oauth2UserService())
+			                ...
+			        )
+			);
 	}
 
 	private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
@@ -501,10 +543,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Login()
-				.userInfoEndpoint()
-					.oidcUserService(this.oidcUserService())
-					...
+			.oauth2Login(oauth2Login ->
+			    oauth2Login
+				    .userInfoEndpoint(userInfoEndpoint ->
+				        userInfoEndpoint
+				            .oidcUserService(this.oidcUserService())
+			                ...
+			        )
+			);
 	}
 
 	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {

+ 5 - 3
docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc

@@ -169,9 +169,11 @@ or in Java configuration
 [source,java]
 ----
 http
-		.authorizeRequests()
-				.antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
-				...
+	.authorizeRequests(authorizeRequests ->
+	    authorizeRequests
+			.antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
+			...
+	);
 ----
 
 In both configurations URLs that match would pass in the path variable (and convert it) into checkUserId method.

+ 116 - 86
docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc

@@ -137,12 +137,12 @@ How does Spring Security know that we want to require all users to be authentica
 ----
 protected void configure(HttpSecurity http) throws Exception {
 	http
-		.authorizeRequests()
-			.anyRequest().authenticated()
-			.and()
-		.formLogin()
-			.and()
-		.httpBasic();
+		.authorizeRequests(authorizeRequests ->
+		    authorizeRequests
+			    .anyRequest().authenticated()
+		)
+		.formLogin(withDefaults())
+		.httpBasic(withDefaults());
 }
 ----
 
@@ -163,10 +163,6 @@ You will notice that this configuration is quite similar the XML Namespace confi
 </http>
 ----
 
-The Java Configuration equivalent of closing an XML tag is expressed using the `and()` method which allows us to continue configuring the parent.
-If you read the code it also makes sense.
-I want to configure authorized requests __and__ configure form login __and__ configure HTTP Basic authentication.
-
 [[jc-form]]
 == Java Configuration and Form Login
 You might be wondering where the login form came from when you were prompted to log in, since we made no mention of any HTML files or JSPs.
@@ -180,12 +176,15 @@ To do so we can update our configuration as seen below:
 ----
 protected void configure(HttpSecurity http) throws Exception {
 	http
-		.authorizeRequests()
-			.anyRequest().authenticated()
-			.and()
-		.formLogin()
-			.loginPage("/login") // <1>
-			.permitAll();        // <2>
+		.authorizeRequests(authorizeRequests ->
+		    authorizeRequests
+			    .anyRequest().authenticated()
+		)
+		.formLogin(formLogin ->
+		    formLogin
+			    .loginPage("/login") // <1>
+			    .permitAll()         // <2>
+	    );
 }
 ----
 
@@ -245,14 +244,14 @@ For example:
 ----
 protected void configure(HttpSecurity http) throws Exception {
 	http
-		.authorizeRequests()                                                                <1>
-			.antMatchers("/resources/**", "/signup", "/about").permitAll()                  <2>
-			.antMatchers("/admin/**").hasRole("ADMIN")                                      <3>
-			.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")            <4>
-			.anyRequest().authenticated()                                                   <5>
-			.and()
-		// ...
-		.formLogin();
+		.authorizeRequests(authorizeRequests ->                                        // <1>
+		    authorizeRequests
+			    .antMatchers("/resources/**", "/signup", "/about").permitAll()         // <2>
+			    .antMatchers("/admin/**").hasRole("ADMIN")                             // <3>
+			    .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")   // <4>
+			    .anyRequest().authenticated()                                          // <5>
+		)
+		.formLogin(withDefaults());
 }
 ----
 
@@ -282,14 +281,15 @@ Similar to configuring login capabilities, however, you also have various option
 ----
 protected void configure(HttpSecurity http) throws Exception {
 	http
-		.logout()                                                                <1>
-			.logoutUrl("/my/logout")                                                 <2>
-			.logoutSuccessUrl("/my/index")                                           <3>
-			.logoutSuccessHandler(logoutSuccessHandler)                              <4>
-			.invalidateHttpSession(true)                                             <5>
-			.addLogoutHandler(logoutHandler)                                         <6>
-			.deleteCookies(cookieNamesToClear)                                       <7>
-			.and()
+		.logout(logout ->                                                       // <1>
+		    logout
+			    .logoutUrl("/my/logout")                                        // <2>
+			    .logoutSuccessUrl("/my/index")                                  // <3>
+			    .logoutSuccessHandler(logoutSuccessHandler)                     // <4>
+			    .invalidateHttpSession(true)                                    // <5>
+			    .addLogoutHandler(logoutHandler)                                // <6>
+			    .deleteCookies(cookieNamesToClear)                              // <7>
+		)
 		...
 }
 ----
@@ -510,11 +510,14 @@ The first is a `WebSecurityConfigurerAdapter` that configures the app as a resou
 ```java
 protected void configure(HttpSecurity http) {
     http
-        .authorizeRequests()
-            .anyRequest().authenticated()
-            .and()
-        .oauth2ResourceServer()
-            .jwt();
+        .authorizeRequests(authorizeRequests ->
+            authorizeRequests
+                .anyRequest().authenticated()
+        )
+        .oauth2ResourceServer(oauth2ResourceServer ->
+            oauth2ResourceServer
+                .jwt(withDefaults())
+        );
 }
 ```
 
@@ -527,13 +530,18 @@ Replacing this is as simple as exposing the bean within the application:
 public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
     protected void configure(HttpSecurity http) {
         http
-            .authorizeRequests()
-                .mvcMatchers("/messages/**").hasAuthority("SCOPE_message:read")
-                .anyRequest().authenticated()
-                .and()
-            .oauth2ResourceServer()
-                .jwt()
-                    .jwtAuthenticationConverter(myConverter());
+            .authorizeRequests(authorizeRequests ->
+                authorizeRequests
+                    .mvcMatchers("/messages/**").hasAuthority("SCOPE_message:read")
+                    .anyRequest().authenticated()
+            )
+            .oauth2ResourceServer(oauth2ResourceServer ->
+                oauth2ResourceServer
+                    .jwt(jwt ->
+                        jwt
+                            .jwtAuthenticationConverter(myConverter())
+                    )
+            );
     }
 }
 ```
@@ -565,12 +573,17 @@ An authorization server's JWK Set Uri can be configured <<oauth2resourceserver-j
 public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
     protected void configure(HttpSecurity http) {
         http
-            .authorizeRequests()
-                .anyRequest().authenticated()
-                .and()
-            .oauth2ResourceServer()
-                .jwt()
-                    .jwkSetUri("https://idp.example.com/.well-known/jwks.json");
+            .authorizeRequests(authorizeRequests ->
+                authorizeRequests
+                    .anyRequest().authenticated()
+            )
+            .oauth2ResourceServer(oauth2ResourceServer ->
+                oauth2ResourceServer
+                    .jwt(jwt ->
+                        jwt
+                            .jwkSetUri("https://idp.example.com/.well-known/jwks.json")
+                    )
+            );
     }
 }
 ```
@@ -587,12 +600,17 @@ More powerful than `jwkSetUri()` is `decoder()`, which will completely replace a
 public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
     protected void configure(HttpSecurity http) {
         http
-            .authorizeRequests()
-                .anyRequest().authenticated()
-                .and()
-            .oauth2ResourceServer()
-                .jwt()
-                    .decoder(myCustomDecoder());
+            .authorizeRequests(authorizeRequests ->
+                authorizeRequests
+                    .anyRequest().authenticated()
+            )
+            .oauth2ResourceServer(oauth2ResourceServer ->
+                oauth2ResourceServer
+                    .jwt(jwt ->
+                        jwt
+                            .decoder(myCustomDecoder())
+                    )
+            );
     }
 }
 ```
@@ -627,13 +645,16 @@ This means that to protect an endpoint or method with a scope derived from a JWT
 public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
     protected void configure(HttpSecurity http) {
         http
-            .authorizeRequests()
-                .mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
-                .mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
-                .anyRequest().authenticated()
-                .and()
-            .oauth2ResourceServer()
-                .jwt();
+            .authorizeRequests(authorizeRequests ->
+                authorizeRequests
+                    .mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
+                    .mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
+                    .anyRequest().authenticated()
+            )
+            .oauth2ResourceServer(oauth2ResourceServer ->
+                oauth2ResourceServer
+                    .jwt(withDefaults())
+            );
     }
 }
 ```
@@ -659,12 +680,17 @@ To this end, the DSL exposes `jwtAuthenticationConverter()`:
 public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
     protected void configure(HttpSecurity http) {
         http
-            .authorizeRequests()
-                .anyRequest().authenticated()
-                .and()
-            .oauth2ResourceServer()
-                .jwt()
-                    .jwtAuthenticationConverter(grantedAuthoritiesExtractor());
+            .authorizeRequests(authorizeRequests ->
+                authorizeRequests
+                    .anyRequest().authenticated()
+            )
+            .oauth2ResourceServer(oauth2ResourceServer ->
+                oauth2ResourceServer
+                    .jwt(jwt ->
+                        jwt
+                            .jwtAuthenticationConverter(grantedAuthoritiesExtractor())
+                    )
+            );
     }
 }
 
@@ -1078,10 +1104,11 @@ public class MultiHttpSecurityConfig {
 		protected void configure(HttpSecurity http) throws Exception {
 			http
 				.antMatcher("/api/**")                               <3>
-				.authorizeRequests()
-					.anyRequest().hasRole("ADMIN")
-					.and()
-				.httpBasic();
+				.authorizeRequests(authorizeRequests ->
+				    authorizeRequests
+					    .anyRequest().hasRole("ADMIN")
+			    )
+				.httpBasic(withDefaults());
 		}
 	}
 
@@ -1091,10 +1118,11 @@ public class MultiHttpSecurityConfig {
 		@Override
 		protected void configure(HttpSecurity http) throws Exception {
 			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.formLogin();
+				.authorizeRequests(authorizeRequests ->
+				    authorizeRequests
+					    .anyRequest().authenticated()
+				)
+				.formLogin(withDefaults());
 		}
 	}
 }
@@ -1221,15 +1249,17 @@ For example, if you wanted to configure the `filterSecurityPublishAuthorizationS
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 	http
-		.authorizeRequests()
-			.anyRequest().authenticated()
-			.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
-				public <O extends FilterSecurityInterceptor> O postProcess(
-						O fsi) {
-					fsi.setPublishAuthorizationSuccess(true);
-					return fsi;
-				}
-			});
+		.authorizeRequests(authorizeRequests ->
+			authorizeRequests
+				.anyRequest().authenticated()
+				.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
+					public <O extends FilterSecurityInterceptor> O postProcess(
+							O fsi) {
+						fsi.setPublishAuthorizationSuccess(true);
+						return fsi;
+					}
+				})
+		);
 }
 ----
 

+ 41 - 24
docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-client.adoc

@@ -20,14 +20,18 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Client()
-				.clientRegistrationRepository(this.clientRegistrationRepository())
-				.authorizedClientRepository(this.authorizedClientRepository())
-				.authorizedClientService(this.authorizedClientService())
-				.authorizationCodeGrant()
-					.authorizationRequestRepository(this.authorizationRequestRepository())
-					.authorizationRequestResolver(this.authorizationRequestResolver())
-					.accessTokenResponseClient(this.accessTokenResponseClient());
+			.oauth2Client(oauth2Client ->
+			    oauth2Client
+				    .clientRegistrationRepository(this.clientRegistrationRepository())
+				    .authorizedClientRepository(this.authorizedClientRepository())
+				    .authorizedClientService(this.authorizedClientService())
+				    .authorizationCodeGrant(authorizationCodeGrant ->
+					    authorizationCodeGrant
+						    .authorizationRequestRepository(this.authorizationRequestRepository())
+						    .authorizationRequestResolver(this.authorizationRequestResolver())
+						    .accessTokenResponseClient(this.accessTokenResponseClient())
+				    )
+			);
 	}
 }
 ----
@@ -245,10 +249,14 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Client()
-				.authorizationCodeGrant()
-					.authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
-					...
+			.oauth2Client(oauth2Client ->
+			    oauth2Client
+				    .authorizationCodeGrant(authorizationCodeGrant ->
+				        authorizationCodeGrant
+					        .authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
+					        ...
+					)
+			);
 	}
 
 	private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
@@ -285,14 +293,19 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.anyRequest().authenticated()
-				.and()
-			.oauth2Login()
-				.authorizationEndpoint()
-					.authorizationRequestResolver(
-							new CustomAuthorizationRequestResolver(
-									this.clientRegistrationRepository));    <1>
+			.authorizeRequests(authorizeRequests ->
+			    authorizeRequests
+				    .anyRequest().authenticated()
+			)
+			.oauth2Login(oauth2Login ->
+				oauth2Login
+					.authorizationEndpoint(authorizationEndpoint ->
+						authorizationEndpoint
+							.authorizationRequestResolver(
+							    new CustomAuthorizationRequestResolver(
+							            this.clientRegistrationRepository))    <1>
+					)
+			);
 	}
 }
 
@@ -422,10 +435,14 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.oauth2Client()
-				.authorizationCodeGrant()
-					.accessTokenResponseClient(this.customAccessTokenResponseClient())
-					...
+			.oauth2Client(oauth2Client ->
+			    oauth2Client
+				    .authorizationCodeGrant(authorizationCodeGrant ->
+				        authorizationCodeGrant
+					        .accessTokenResponseClient(this.customAccessTokenResponseClient())
+					        ...
+					 )
+			);
 	}
 
 	private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> customAccessTokenResponseClient() {

+ 15 - 12
docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-login.adoc

@@ -285,10 +285,11 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.anyRequest().authenticated()
-				.and()
-			.oauth2Login();
+			.authorizeRequests(authorizeRequests ->
+			    authorizeRequests
+				    .anyRequest().authenticated()
+			)
+			.oauth2Login(withDefaults());
 	}
 }
 ----
@@ -310,10 +311,11 @@ public class OAuth2LoginConfig {
 		@Override
 		protected void configure(HttpSecurity http) throws Exception {
 			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.oauth2Login();
+				.authorizeRequests(authorizeRequests ->
+				    authorizeRequests
+					    .anyRequest().authenticated()
+				)
+				.oauth2Login(withDefaults());
 		}
 	}
 
@@ -358,10 +360,11 @@ public class OAuth2LoginConfig {
 		@Override
 		protected void configure(HttpSecurity http) throws Exception {
 			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.oauth2Login();
+				.authorizeRequests(authorizeRequests ->
+				    authorizeRequests
+					    .anyRequest().authenticated()
+				)
+				.oauth2Login(withDefaults());
 		}
 	}
 

+ 2 - 2
docs/manual/src/docs/asciidoc/_includes/servlet/web/cors.adoc

@@ -18,7 +18,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 	protected void configure(HttpSecurity http) throws Exception {
 		http
 			// by default uses a Bean by the name of corsConfigurationSource
-			.cors().and()
+			.cors(withDefaults())
 			...
 	}
 
@@ -59,7 +59,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 		http
 			// if Spring MVC is on classpath and no CorsConfigurationSource is provided,
 			// Spring Security will use CORS configuration provided to Spring MVC
-			.cors().and()
+			.cors(withDefaults())
 			...
 	}
 }

+ 11 - 5
docs/manual/src/docs/asciidoc/_includes/servlet/web/csrf.adoc

@@ -187,7 +187,9 @@ WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.csrf().disable();
+			.csrf(csrf ->
+			    csrf.disable()
+			);
 	}
 }
 ----
@@ -314,8 +316,10 @@ public class WebSecurityConfig extends
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.csrf()
-				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
+			.csrf(csrf ->
+			    csrf
+				    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
+			);
 	}
 }
 ----
@@ -391,8 +395,10 @@ WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.logout()
-				.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
+			.logout(logout ->
+			    logout
+				    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
+			);
 	}
 }
 ----

+ 179 - 124
docs/manual/src/docs/asciidoc/_includes/servlet/web/headers.adoc

@@ -60,9 +60,15 @@ public class WebSecurityConfig extends
 	protected void configure(HttpSecurity http) throws Exception {
 		http
 			// ...
-			.headers()
-				.frameOptions().sameOrigin()
-				.httpStrictTransportSecurity().disable();
+			.headers(headers ->
+			    headers
+				    .frameOptions(frameOptions ->
+				        frameOptions.sameOrigin()
+				    )
+				    .httpStrictTransportSecurity(hsts ->
+				        hsts.disable()
+				    )
+			);
 	}
 }
 ----
@@ -92,15 +98,17 @@ If you are using Spring Security's Java Configuration the following will only ad
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		// do not use any default headers unless explicitly listed
-		.defaultsDisabled()
-		.cacheControl();
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    // do not use any default headers unless explicitly listed
+                    .defaultsDisabled()
+                    .cacheControl(withDefaults())
+            );
+    }
 }
 ----
 
@@ -126,12 +134,14 @@ If necessary, you can disable all of the HTTP Security response headers with the
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers().disable();
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers.disable()
+            );
+    }
 }
 ----
 
@@ -182,14 +192,16 @@ Similarly, you can enable only cache control within Java Configuration with the
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.defaultsDisabled()
-		.cacheControl();
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .defaultsDisabled()
+                    .cacheControl(withDefaults())
+            );
+    }
 }
 ----
 
@@ -263,14 +275,16 @@ If you want more control over the headers, you can explicitly specify the conten
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.defaultsDisabled()
-		.contentTypeOptions();
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .defaultsDisabled()
+                    .contentTypeOptions(withDefaults())
+            );
+    }
 }
 ----
 
@@ -327,16 +341,20 @@ Similarly, you can enable only HSTS headers with Java Configuration:
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.httpStrictTransportSecurity()
-			.includeSubdomains(true)
-			.preload(true)
-			.maxAgeSeconds(31536000);
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .httpStrictTransportSecurity(hsts ->
+                        hsts
+                            .includeSubDomains(true)
+                            .preload(true)
+                            .maxAgeInSeconds(31536000)
+                    )
+            );
+    }
 }
 ----
 
@@ -399,16 +417,20 @@ Similarly, you can enable HPKP headers with Java Configuration:
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-		@Override
-		protected void configure(HttpSecurity http) throws Exception {
-				http
-				// ...
-				.headers()
-						.httpPublicKeyPinning()
-								.includeSubdomains(true)
-								.reportUri("https://example.net/pkp-report")
-								.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
-		}
+	@Override
+	protected void configure(HttpSecurity http) throws Exception {
+		http
+			// ...
+			.headers(headers ->
+			    headers
+					.httpPublicKeyPinning(hpkp ->
+					    hpkp
+							.includeSubDomains(true)
+							.reportUri("https://example.net/pkp-report")
+							.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=")
+				    )
+			);
+	}
 }
 ----
 
@@ -461,14 +483,18 @@ Similarly, you can customize frame options to use the same origin within Java Co
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.frameOptions()
-			.sameOrigin();
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .frameOptions(frameOptions ->
+                        frameOptions
+                            .sameOrigin()
+                    )
+            );
+    }
 }
 ----
 
@@ -511,14 +537,18 @@ Similarly, you can customize XSS protection within Java Configuration with the f
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.xssProtection()
-			.block(false);
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .xssProtection(xssProtection ->
+                        xssProtection
+                            .block(false)
+                    )
+            );
+    }
 }
 ----
 
@@ -625,13 +655,18 @@ Similarly, you can enable the CSP header using Java configuration as shown below
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.contentSecurityPolicy("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/");
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .contentSecurityPolicy(csp ->
+                        csp
+                            .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
+                       )
+            );
+    }
 }
 ----
 
@@ -643,14 +678,19 @@ To enable the CSP _'report-only'_ header, provide the following Java configurati
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.contentSecurityPolicy("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
-		.reportOnly();
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .contentSecurityPolicy(csp ->
+                        csp
+                            .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
+                            .reportOnly()
+                    )
+            );
+    }
 }
 ----
 
@@ -707,13 +747,18 @@ Similarly, you can enable the Referrer Policy header using Java configuration as
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .referrerPolicy(referrerPolicy ->
+                        referrerPolicy
+                            .policy(ReferrerPolicy.SAME_ORIGIN)
+                    )
+            );
+    }
 }
 ----
 
@@ -757,13 +802,15 @@ Similarly, you can enable the Feature Policy header using Java configuration as
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.featurePolicy("geolocation 'self'");
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .featurePolicy("geolocation 'self'")
+            );
+    }
 }
 ----
 
@@ -804,13 +851,15 @@ Similarly, the headers could be added to the response using Java Configuration a
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"));
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
+            );
+    }
 }
 ----
 
@@ -849,13 +898,15 @@ We could also restrict framing of content to the same origin with Java configura
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	http
-	// ...
-	.headers()
-		.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN));
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
+            );
+    }
 }
 ----
 
@@ -903,17 +954,21 @@ We could also prevent framing of content to the log in page using java configura
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-@Override
-protected void configure(HttpSecurity http) throws Exception {
-	RequestMatcher matcher = new AntPathRequestMatcher("/login");
-	DelegatingRequestMatcherHeaderWriter headerWriter =
-		new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
-	http
-	// ...
-	.headers()
-		.frameOptions().disabled()
-		.addHeaderWriter(headerWriter);
-}
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        RequestMatcher matcher = new AntPathRequestMatcher("/login");
+        DelegatingRequestMatcherHeaderWriter headerWriter =
+            new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
+        http
+            // ...
+            .headers(headers ->
+                headers
+                    .frameOptions(frameOptions ->
+                        frameOptions.disable()
+                    )
+                    .addHeaderWriter(headerWriter)
+            );
+    }
 }
 ----
 

+ 23 - 14
docs/manual/src/docs/asciidoc/_includes/servlet/web/websocket.adoc

@@ -323,9 +323,13 @@ public class WebSecurityConfig extends
   protected void configure(HttpSecurity http) throws Exception {
     http
       // ...
-      .headers()
-        .frameOptions()
-            .sameOrigin();
+      .headers(headers ->
+        headers
+          .frameOptions(frameOptions ->
+             frameOptions
+               .sameOrigin()
+          )
+      );
   }
 }
 ----
@@ -356,18 +360,23 @@ public class WebSecurityConfig
 
     @Override
     protected void configure(HttpSecurity http) throws Exception {
-
         http
-            .csrf()
-                // ignore our stomp endpoints since they are protected using Stomp headers
-                .ignoringAntMatchers("/chat/**")
-                .and()
-            .headers()
-                // allow same origin to frame our site to support iframe SockJS
-                .frameOptions().sameOrigin()
-                .and()
-            .authorizeRequests()
-
+            .csrf(csrf ->
+                csrf
+                    // ignore our stomp endpoints since they are protected using Stomp headers
+                    .ignoringAntMatchers("/chat/**")
+            )
+            .headers(headers ->
+                headers
+                    // allow same origin to frame our site to support iframe SockJS
+                    .frameOptions(frameOptions ->
+                        frameOptions
+                            .sameOrigin()
+                    )
+            )
+            .authorizeRequests(authorizeRequests ->
+                ...
+            )
             ...
 ----
 

+ 11 - 6
samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,11 +32,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-				.authorizeRequests()
-					.antMatchers("/css/**", "/index").permitAll()
-					.antMatchers("/user/**").hasRole("USER")
-					.and()
-				.formLogin().loginPage("/login").failureUrl("/login-error");
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.antMatchers("/css/**", "/index").permitAll()
+						.antMatchers("/user/**").hasRole("USER")
+				)
+				.formLogin(formLogin ->
+					formLogin
+						.loginPage("/login")
+						.failureUrl("/login-error")
+				);
 	}
 	// @formatter:on
 

+ 16 - 10
samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -358,15 +358,21 @@ public class OAuth2LoginApplicationTests {
 		@Override
 		protected void configure(HttpSecurity http) throws Exception {
 			http
-				.authorizeRequests()
-					.anyRequest().authenticated()
-					.and()
-				.oauth2Login()
-					.tokenEndpoint()
-						.accessTokenResponseClient(this.mockAccessTokenResponseClient())
-						.and()
-					.userInfoEndpoint()
-						.userService(this.mockUserService());
+				.authorizeRequests(authorizeRequests ->
+					authorizeRequests
+						.anyRequest().authenticated()
+				)
+				.oauth2Login(oauth2Login ->
+					oauth2Login
+						.tokenEndpoint(tokenEndpoint ->
+							tokenEndpoint
+								.accessTokenResponseClient(this.mockAccessTokenResponseClient())
+						)
+						.userInfoEndpoint(userInfoEndpoint ->
+							userInfoEndpoint
+								.userService(this.mockUserService())
+						)
+				);
 		}
 		// @formatter:on
 

+ 12 - 7
samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,6 +46,8 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
 import org.springframework.security.oauth2.jwt.JwtDecoder;
 import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
 
+import static org.springframework.security.config.Customizer.withDefaults;
+
 /**
  * @author Josh Cummings
  */
@@ -66,12 +68,15 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
 	protected void configure(HttpSecurity http) throws Exception {
 		// @formatter:off
 		http
-			.authorizeRequests()
-				.antMatchers("/message/**").hasAuthority("SCOPE_message:read")
-				.anyRequest().authenticated()
-				.and()
-			.oauth2ResourceServer()
-				.jwt();
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/message/**").hasAuthority("SCOPE_message:read")
+					.anyRequest().authenticated()
+			)
+			.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer
+					.jwt(withDefaults())
+			);
 		// @formatter:on
 	}
 

+ 9 - 6
samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java

@@ -51,12 +51,15 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
 	protected void configure(HttpSecurity http) throws Exception {
 		// @formatter:off
 		http
-			.authorizeRequests()
-				.antMatchers("/**/message/**").hasAuthority("SCOPE_message:read")
-				.anyRequest().authenticated()
-				.and()
-			.oauth2ResourceServer()
-				.authenticationManagerResolver(multitenantAuthenticationManager());
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/**/message/**").hasAuthority("SCOPE_message:read")
+					.anyRequest().authenticated()
+			)
+			.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer
+					.authenticationManagerResolver(multitenantAuthenticationManager())
+			);
 		// @formatter:on
 	}
 

+ 13 - 8
samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java

@@ -34,14 +34,19 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
 	protected void configure(HttpSecurity http) throws Exception {
 		// @formatter:off
 		http
-			.authorizeRequests()
-				.mvcMatchers("/message/**").hasAuthority("SCOPE_message:read")
-				.anyRequest().authenticated()
-				.and()
-			.oauth2ResourceServer()
-				.opaqueToken()
-					.introspectionUri(this.introspectionUri)
-					.introspectionClientCredentials(this.clientId, this.clientSecret);
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.mvcMatchers("/message/**").hasAuthority("SCOPE_message:read")
+					.anyRequest().authenticated()
+			)
+			.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer
+					.opaqueToken(opaqueToken ->
+						opaqueToken
+							.introspectionUri(this.introspectionUri)
+							.introspectionClientCredentials(this.clientId, this.clientSecret)
+					)
+			);
 		// @formatter:on
 	}
 }

+ 11 - 7
samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java

@@ -38,13 +38,17 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
 	protected void configure(HttpSecurity http) throws Exception {
 		// @formatter:off
 		http
-			.authorizeRequests()
-				.antMatchers("/message/**").hasAuthority("SCOPE_message:read")
-				.anyRequest().authenticated()
-				.and()
-			.oauth2ResourceServer()
-				.jwt()
-					.decoder(jwtDecoder());
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/message/**").hasAuthority("SCOPE_message:read")
+					.anyRequest().authenticated()
+			)
+			.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer
+					.jwt(jwt ->
+						jwt.decoder(jwtDecoder())
+					)
+			);
 		// @formatter:on
 	}
 

+ 12 - 7
samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
+import static org.springframework.security.config.Customizer.withDefaults;
+
 /**
  * @author Josh Cummings
  */
@@ -29,12 +31,15 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
 	protected void configure(HttpSecurity http) throws Exception {
 		// @formatter:off
 		http
-			.authorizeRequests()
-				.antMatchers("/message/**").hasAuthority("SCOPE_message:read")
-				.anyRequest().authenticated()
-				.and()
-			.oauth2ResourceServer()
-				.jwt();
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/message/**").hasAuthority("SCOPE_message:read")
+					.anyRequest().authenticated()
+			)
+			.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer
+					.jwt(withDefaults())
+			);
 		// @formatter:on
 	}
 }

+ 11 - 10
samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
+import static org.springframework.security.config.Customizer.withDefaults;
+
 /**
  * @author Joe Grandja
  */
@@ -33,15 +35,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.mvcMatchers("/", "/public/**").permitAll()
-				.anyRequest().authenticated()
-				.and()
-			.formLogin()
-				.and()
-			.oauth2Login()
-				.and()
-			.oauth2Client();
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.mvcMatchers("/", "/public/**").permitAll()
+					.anyRequest().authenticated()
+			)
+			.formLogin(withDefaults())
+			.oauth2Login(withDefaults())
+			.oauth2Client(withDefaults());
 	}
 
 	@Bean

+ 16 - 9
samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
+import static org.springframework.security.config.Customizer.withDefaults;
+
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
@@ -40,14 +42,19 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	protected void configure(
 			HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.anyRequest().authenticated()
-				.and()
-			.formLogin()
-				.and()
-			.sessionManagement()
-				.maximumSessions(1)
-					.expiredUrl("/login?expired");
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.anyRequest().authenticated()
+			)
+			.formLogin(withDefaults())
+			.sessionManagement(sessionManagement ->
+				sessionManagement
+					.sessionConcurrency(sessionConcurrency ->
+						sessionConcurrency
+							.maximumSessions(1)
+							.expiredUrl("/login?expired")
+					)
+			);
 	}
 	// @formatter:on
 }

+ 15 - 11
samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,16 +29,20 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.antMatchers("/resources/**").permitAll()
-				.anyRequest().authenticated()
-				.and()
-			.formLogin()
-				.loginPage("/login")
-				.permitAll()
-				.and()
-			.logout()
-				.permitAll();
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/resources/**").permitAll()
+					.anyRequest().authenticated()
+			)
+			.formLogin(formLogin ->
+				formLogin
+					.loginPage("/login")
+					.permitAll()
+			)
+			.logout(logout ->
+				logout
+					.permitAll()
+			);
 	}
 	// @formatter:on
 

+ 66 - 41
samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,46 +26,71 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.antMatchers("/resources/**").permitAll()
-				.anyRequest().authenticated()
-				.and()
-			.openidLogin()
-				.loginPage("/login")
-				.permitAll()
-				.authenticationUserDetailsService(new CustomUserDetailsService())
-				.attributeExchange("https://www.google.com/.*")
-					.attribute("email")
-						.type("https://axschema.org/contact/email")
-						.required(true)
-						.and()
-					.attribute("firstname")
-						.type("https://axschema.org/namePerson/first")
-						.required(true)
-						.and()
-					.attribute("lastname")
-						.type("https://axschema.org/namePerson/last")
-						.required(true)
-						.and()
-					.and()
-				.attributeExchange(".*yahoo.com.*")
-					.attribute("email")
-						.type("https://axschema.org/contact/email")
-						.required(true)
-						.and()
-					.attribute("fullname")
-						.type("https://axschema.org/namePerson")
-						.required(true)
-						.and()
-					.and()
-				.attributeExchange(".*myopenid.com.*")
-					.attribute("email")
-						.type("https://schema.openid.net/contact/email")
-						.required(true)
-						.and()
-					.attribute("fullname")
-						.type("https://schema.openid.net/namePerson")
-						.required(true);
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/resources/**").permitAll()
+					.anyRequest().authenticated()
+			)
+			.openidLogin(openidLogin ->
+				openidLogin
+					.loginPage("/login")
+					.permitAll()
+					.authenticationUserDetailsService(new CustomUserDetailsService())
+					.attributeExchange(googleExchange ->
+						googleExchange
+							.identifierPattern("https://www.google.com/.*")
+							.attribute(emailAttribute ->
+								emailAttribute
+									.name("email")
+									.type("https://axschema.org/contact/email")
+									.required(true)
+							)
+							.attribute(firstnameAttribute ->
+								firstnameAttribute
+									.name("firstname")
+									.type("https://axschema.org/namePerson/first")
+									.required(true)
+							)
+							.attribute(lastnameAttribute ->
+								lastnameAttribute
+									.name("lastname")
+									.type("https://axschema.org/namePerson/last")
+									.required(true)
+							)
+					)
+					.attributeExchange(yahooExchange ->
+						yahooExchange
+							.identifierPattern(".*yahoo.com.*")
+							.attribute(emailAttribute ->
+								emailAttribute
+									.name("email")
+									.type("https://axschema.org/contact/email")
+									.required(true)
+							)
+							.attribute(fullnameAttribute ->
+								fullnameAttribute
+									.name("fullname")
+									.type("https://axschema.org/namePerson")
+									.required(true)
+							)
+					)
+					.attributeExchange(myopenidExchange ->
+						myopenidExchange
+							.identifierPattern(".*myopenid.com.*")
+							.attribute(emailAttribute ->
+								emailAttribute
+									.name("email")
+									.type("https://schema.openid.net/contact/email")
+									.required(true)
+							)
+							.attribute(fullnameAttribute ->
+									fullnameAttribute
+									.name("fullname")
+									.type("https://schema.openid.net/namePerson")
+									.required(true)
+							)
+					)
+			);
 	}
 	// @formatter:on
 }

+ 10 - 7
samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,12 +26,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.antMatchers("/login", "/resources/**").permitAll()
-				.anyRequest().authenticated()
-				.and()
-			.jee()
-				.mappableRoles("USER", "ADMIN");
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/login", "/resources/**").permitAll()
+					.anyRequest().authenticated()
+			)
+			.jee(jee ->
+				jee
+					.mappableRoles("USER", "ADMIN")
+			);
 	}
 	// @formatter:on
 }

+ 14 - 10
samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
+import static org.springframework.security.config.Customizer.withDefaults;
+
 @EnableWebSecurity
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
@@ -39,15 +41,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.antMatchers("/resources/**").permitAll()
-				.anyRequest().authenticated()
-				.and()
-			.formLogin()
-				.loginPage("/login")
-				.permitAll()
-				.and()
-			.rememberMe();
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.antMatchers("/resources/**").permitAll()
+					.anyRequest().authenticated()
+			)
+			.formLogin(formLogin ->
+				formLogin
+					.loginPage("/login")
+					.permitAll()
+			)
+			.rememberMe(withDefaults());
 	}
 	// @formatter:on
 }

+ 8 - 5
samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
+import static org.springframework.security.config.Customizer.withDefaults;
+
 @EnableWebSecurity
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
@@ -40,10 +42,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
-			.authorizeRequests()
-				.anyRequest().authenticated()
-				.and()
-			.x509();
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests
+					.anyRequest().authenticated()
+			)
+			.x509(withDefaults());
 	}
 	// @formatter:on
 }

+ 10 - 0
web/src/main/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriter.java

@@ -81,10 +81,20 @@ public final class ContentSecurityPolicyHeaderWriter implements HeaderWriter {
 
 	private static final String CONTENT_SECURITY_POLICY_REPORT_ONLY_HEADER = "Content-Security-Policy-Report-Only";
 
+	private static final String DEFAULT_SRC_SELF_POLICY = "default-src 'self'";
+
 	private String policyDirectives;
 
 	private boolean reportOnly;
 
+	/**
+	 * Creates a new instance. Default value: default-src 'self'
+	 */
+	public ContentSecurityPolicyHeaderWriter() {
+		setPolicyDirectives(DEFAULT_SRC_SELF_POLICY);
+		this.reportOnly = false;
+	}
+
 	/**
 	 * Creates a new instance
 	 *

+ 19 - 0
web/src/test/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriterTests.java

@@ -43,6 +43,15 @@ public class ContentSecurityPolicyHeaderWriterTests {
 		writer = new ContentSecurityPolicyHeaderWriter(DEFAULT_POLICY_DIRECTIVES);
 	}
 
+	@Test
+	public void writeHeadersWhenNoPolicyDirectivesThenUsesDefault() {
+		ContentSecurityPolicyHeaderWriter noPolicyWriter = new ContentSecurityPolicyHeaderWriter();
+		noPolicyWriter.writeHeaders(request, response);
+
+		assertThat(response.getHeaderNames()).hasSize(1);
+		assertThat(response.getHeader("Content-Security-Policy")).isEqualTo(DEFAULT_POLICY_DIRECTIVES);
+	}
+
 	@Test
 	public void writeHeadersContentSecurityPolicyDefault() {
 		writer.writeHeaders(request, response);
@@ -64,6 +73,16 @@ public class ContentSecurityPolicyHeaderWriterTests {
 		assertThat(response.getHeader("Content-Security-Policy")).isEqualTo(policyDirectives);
 	}
 
+	@Test
+	public void writeHeadersWhenNoPolicyDirectivesReportOnlyThenUsesDefault() {
+		ContentSecurityPolicyHeaderWriter noPolicyWriter = new ContentSecurityPolicyHeaderWriter();
+		writer.setReportOnly(true);
+		noPolicyWriter.writeHeaders(request, response);
+
+		assertThat(response.getHeaderNames()).hasSize(1);
+		assertThat(response.getHeader("Content-Security-Policy")).isEqualTo(DEFAULT_POLICY_DIRECTIVES);
+	}
+
 	@Test
 	public void writeHeadersContentSecurityPolicyReportOnlyDefault() {
 		writer.setReportOnly(true);

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно