Bladeren bron

Remove include servlet/saml2/index.adoc

Rob Winch 4 jaren geleden
bovenliggende
commit
b8a362a60f
31 gewijzigde bestanden met toevoegingen van 1981 en 367 verwijderingen
  1. 1 1
      docs/modules/ROOT/pages/overview/whats-new.adoc
  2. 41 41
      docs/modules/ROOT/pages/servlet/appendix/faq.adoc
  3. 130 130
      docs/modules/ROOT/pages/servlet/appendix/namespace.adoc
  4. 1 1
      docs/modules/ROOT/pages/servlet/appendix/proxy-server.adoc
  5. 5 5
      docs/modules/ROOT/pages/servlet/authentication/anonymous.adoc
  6. 11 11
      docs/modules/ROOT/pages/servlet/authentication/cas.adoc
  7. 3 3
      docs/modules/ROOT/pages/servlet/authentication/events.adoc
  8. 10 10
      docs/modules/ROOT/pages/servlet/authentication/jaas.adoc
  9. 6 6
      docs/modules/ROOT/pages/servlet/authentication/logout.adoc
  10. 2 2
      docs/modules/ROOT/pages/servlet/authentication/openid.adoc
  11. 10 10
      docs/modules/ROOT/pages/servlet/authentication/preauth.adoc
  12. 7 7
      docs/modules/ROOT/pages/servlet/authentication/rememberme.adoc
  13. 3 3
      docs/modules/ROOT/pages/servlet/authentication/runas.adoc
  14. 8 8
      docs/modules/ROOT/pages/servlet/authentication/session-management.adoc
  15. 4 4
      docs/modules/ROOT/pages/servlet/authentication/x509.adoc
  16. 4 4
      docs/modules/ROOT/pages/servlet/authorization/acls.adoc
  17. 13 13
      docs/modules/ROOT/pages/servlet/authorization/expression-based.adoc
  18. 8 8
      docs/modules/ROOT/pages/servlet/authorization/method-security.adoc
  19. 4 4
      docs/modules/ROOT/pages/servlet/authorization/secure-objects.adoc
  20. 4 4
      docs/modules/ROOT/pages/servlet/integrations/concurrency.adoc
  21. 1 1
      docs/modules/ROOT/pages/servlet/integrations/cors.adoc
  22. 3 3
      docs/modules/ROOT/pages/servlet/integrations/data.adoc
  23. 1 1
      docs/modules/ROOT/pages/servlet/integrations/jackson.adoc
  24. 8 8
      docs/modules/ROOT/pages/servlet/integrations/jsp-taglibs.adoc
  25. 1 1
      docs/modules/ROOT/pages/servlet/integrations/localization.adoc
  26. 8 8
      docs/modules/ROOT/pages/servlet/integrations/mvc.adoc
  27. 13 13
      docs/modules/ROOT/pages/servlet/integrations/servlet-api.adoc
  28. 16 16
      docs/modules/ROOT/pages/servlet/integrations/websocket.adoc
  29. 1615 1
      docs/modules/ROOT/pages/servlet/saml2/index.adoc
  30. 7 7
      docs/modules/ROOT/pages/servlet/test/method.adoc
  31. 33 33
      docs/modules/ROOT/pages/servlet/test/mockmvc.adoc

+ 1 - 1
docs/modules/ROOT/pages/overview/whats-new.adoc

@@ -1,5 +1,5 @@
 [[new]]
-== What's New in Spring Security 5.6
+= What's New in Spring Security 5.6
 
 Spring Security 5.6 provides a number of new features.
 Below are the highlights of the release.

+ 41 - 41
docs/modules/ROOT/pages/servlet/appendix/faq.adoc

@@ -1,5 +1,5 @@
 [[appendix-faq]]
-== Spring Security FAQ
+= Spring Security FAQ
 
 * <<appendix-faq-general-questions>>
 * <<appendix-faq-common-problems>>
@@ -7,7 +7,7 @@
 * <<appendix-faq-howto>>
 
 [[appendix-faq-general-questions]]
-=== General Questions
+== General Questions
 
 . <<appendix-faq-other-concerns>>
 . <<appendix-faq-web-xml>>
@@ -16,7 +16,7 @@
 
 
 [[appendix-faq-other-concerns]]
-==== Will Spring Security take care of all my application security requirements?
+=== Will Spring Security take care of all my application security requirements?
 
 Spring Security provides you with a very flexible framework for your authentication and authorization requirements, but there are many other considerations for building a secure application that are outside its scope.
 Web applications are vulnerable to all kinds of attacks which you should be familiar with, preferably before you start development so you can design and code with them in mind from the beginning.
@@ -24,7 +24,7 @@ Check out the https://www.owasp.org/[OWASP web site] for information on the majo
 
 
 [[appendix-faq-web-xml]]
-==== Why not just use web.xml security?
+=== Why not just use web.xml security?
 
 Let's assume you're developing an enterprise application based on Spring.
 There are four security concerns you typically need to address: authentication, web request security, service layer security (i.e. your methods that implement business logic), and domain object instance security (i.e. different domain objects have different permissions). With these typical requirements in mind:
@@ -64,7 +64,7 @@ Although when considered within the context of web container portability, config
 
 
 [[appendix-faq-requirements]]
-==== What Java and Spring Framework versions are required?
+=== What Java and Spring Framework versions are required?
 
 Spring Security 3.0 and 3.1 require at least JDK 1.5 and also require Spring 3.0.3 as a minimum.
 Ideally you should be using the latest release versions to avoid problems.
@@ -74,7 +74,7 @@ It should also be compatible with applications using Spring 2.5.x.
 
 
 [[appendix-faq-start-simple]]
-==== I'm new to Spring Security and I need to build an application that supports CAS single sign-on over HTTPS, while allowing Basic authentication locally for certain URLs, authenticating against multiple back end user information sources (LDAP and JDBC). I've copied some configuration files I found but it doesn't work.
+=== I'm new to Spring Security and I need to build an application that supports CAS single sign-on over HTTPS, while allowing Basic authentication locally for certain URLs, authenticating against multiple back end user information sources (LDAP and JDBC). I've copied some configuration files I found but it doesn't work.
 What could be wrong?
 
 Or substitute an alternative complex scenario...
@@ -92,7 +92,7 @@ This will take you through a series of steps to get up and running and get some
 If you are using other technologies which you aren't familiar with then you should do some research and try to make sure you can use them in isolation before combining them in a complex system.
 
 [[appendix-faq-common-problems]]
-=== Common Problems
+== Common Problems
 
 . Authentication
 .. <<appendix-faq-bad-credentials>>
@@ -115,7 +115,7 @@ If you are using other technologies which you aren't familiar with then you shou
 .. <<appendix-faq-method-security-with-taglib>>
 
 [[appendix-faq-bad-credentials]]
-==== When I try to log in, I get an error message that says "Bad Credentials". What's wrong?
+=== When I try to log in, I get an error message that says "Bad Credentials". What's wrong?
 
 This means that authentication has failed.
 It doesn't say why, as it is good practice to avoid giving details which might help an attacker guess account names or passwords.
@@ -129,7 +129,7 @@ If you are using hashed passwords, make sure the value stored in your database i
 
 
 [[appendix-faq-login-loop]]
-==== My application goes into an "endless loop" when I try to login, what's going on?
+=== My application goes into an "endless loop" when I try to login, what's going on?
 
 A common user problem with infinite loop and redirecting to the login page is caused by accidentally configuring the login page as a "secured" resource.
 Make sure your configuration allows anonymous access to the login page, either by excluding it from the security filter chain or marking it as requiring ROLE_ANONYMOUS.
@@ -140,7 +140,7 @@ From Spring Security 2.0.1 onwards, when you are using namespace-based configura
 
 
 [[appendix-faq-anon-access-denied]]
-==== I get an exception with the message "Access is denied (user is anonymous);". What's wrong?
+=== I get an exception with the message "Access is denied (user is anonymous);". What's wrong?
 
 This is a debug level message which occurs the first time an anonymous user attempts to access a protected resource.
 
@@ -158,7 +158,7 @@ It is normal and shouldn't be anything to worry about.
 
 
 [[appendix-faq-cached-secure-page]]
-==== Why can I still see a secured page even after I've logged out of my application?
+=== Why can I still see a secured page even after I've logged out of my application?
 
 The most common reason for this is that your browser has cached the page and you are seeing a copy which is being retrieved from the browsers cache.
 Verify this by checking whether the browser is actually sending the request (check your server access logs, the debug log or use a suitable browser debugging plugin such as "Tamper Data" for Firefox). This has nothing to do with Spring Security and you should configure your application or server to set the appropriate `Cache-Control` response headers.
@@ -166,7 +166,7 @@ Note that SSL requests are never cached.
 
 
 [[auth-exception-credentials-not-found]]
-==== I get an exception with the message "An Authentication object was not found in the SecurityContext". What's wrong?
+=== I get an exception with the message "An Authentication object was not found in the SecurityContext". What's wrong?
 
 This is a another debug level message which occurs the first time an anonymous user attempts to access a protected resource, but when you do not have an `AnonymousAuthenticationFilter` in your filter chain configuration.
 
@@ -184,7 +184,7 @@ It is normal and shouldn't be anything to worry about.
 
 
 [[appendix-faq-ldap-authentication]]
-==== I can't get LDAP authentication to work.
+=== I can't get LDAP authentication to work.
 What's wrong with my configuration?
 
 Note that the permissions for an LDAP directory often do not allow you to read the password for a user.
@@ -232,7 +232,7 @@ fun ldapAuthenticationIsSuccessful() {
 ----
 ====
 
-==== Session Management
+=== Session Management
 
 Session management issues are a common source of forum questions.
 If you are developing Java web applications, you should understand how the session is maintained between the servlet container and the user's browser.
@@ -242,7 +242,7 @@ This is entirely handled by the servlet container.
 
 
 [[appendix-faq-concurrent-session-same-browser]]
-==== I'm using Spring Security's concurrent session control to prevent users from logging in more than once at a time.
+=== I'm using Spring Security's concurrent session control to prevent users from logging in more than once at a time.
 When I open another browser window after logging in, it doesn't stop me from logging in again.
 Why can I log in more than once?
 
@@ -256,7 +256,7 @@ If they are already authenticated with the same session, then re-authenticating
 
 
 [[appendix-faq-new-session-on-authentication]]
-==== Why does the session Id change when I authenticate through Spring Security?
+=== Why does the session Id change when I authenticate through Spring Security?
 
 With the default configuration, Spring Security changes the session ID when the user authenticates.
 If you're using a Servlet 3.1 or newer container, the session ID is simply changed.
@@ -266,7 +266,7 @@ You can find more about this online and in the reference manual.
 
 
 [[appendix-faq-tomcat-https-session]]
-==== I'm using Tomcat (or some other servlet container) and have enabled HTTPS for my login page, switching back to HTTP afterwards.
+=== I'm using Tomcat (or some other servlet container) and have enabled HTTPS for my login page, switching back to HTTP afterwards.
 It doesn't work - I just end up back at the login page after authenticating.
 
 This happens because sessions created under HTTPS, for which the session cookie is marked as "secure", cannot subsequently be used under HTTP. The browser will not send the cookie back to the server and any session state will be lost (including the security context information). Starting a session in HTTP first should work as the session cookie won't be marked as secure.
@@ -278,13 +278,13 @@ Even clicking on an HTTPS link from a page accessed over HTTP is potentially ris
 If you need more convincing, check out a tool like https://github.com/moxie0/sslstrip/[sslstrip].
 
 
-==== I'm not switching between HTTP and HTTPS but my session is still getting lost
+=== I'm not switching between HTTP and HTTPS but my session is still getting lost
 
 Sessions are maintained either by exchanging a session cookie or by adding a `jsessionid` parameter to URLs (this happens automatically if you are using JSTL to output URLs, or if you call `HttpServletResponse.encodeUrl` on URLs (before a redirect, for example). If clients have cookies disabled, and you are not rewriting URLs to include the `jsessionid`, then the session will be lost.
 Note that the use of cookies is preferred for security reasons, as it does not expose the session information in the URL.
 
 [[appendix-faq-session-listener-missing]]
-==== I'm trying to use the concurrent session-control support but it won't let me log back in, even if I'm sure I've logged out and haven't exceeded the allowed sessions.
+=== I'm trying to use the concurrent session-control support but it won't let me log back in, even if I'm sure I've logged out and haven't exceeded the allowed sessions.
 
 Make sure you have added the listener to your web.xml file.
 It is essential to make sure that the Spring Security session registry is notified when a session is destroyed.
@@ -299,7 +299,7 @@ Without it, the session information will not be removed from the registry.
 ----
 
 [[appendix-faq-unwanted-session-creation]]
-==== Spring Security is creating a session somewhere, even though I've configured it not to, by setting the create-session attribute to never.
+=== Spring Security is creating a session somewhere, even though I've configured it not to, by setting the create-session attribute to never.
 
 This usually means that the user's application is creating a session somewhere, but that they aren't aware of it.
 The most common culprit is a JSP. Many people aren't aware that JSPs create sessions by default.
@@ -308,19 +308,19 @@ To prevent a JSP from creating a session, add the directive `<%@ page session="f
 If you are having trouble working out where a session is being created, you can add some debugging code to track down the location(s). One way to do this would be to add a `javax.servlet.http.HttpSessionListener` to your application, which calls `Thread.dumpStack()` in the `sessionCreated` method.
 
 [[appendix-faq-forbidden-csrf]]
-==== I get a 403 Forbidden when performing a POST
+=== I get a 403 Forbidden when performing a POST
 
 If an HTTP 403 Forbidden is returned for HTTP POST, but works for HTTP GET then the issue is most likely related to https://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#csrf[CSRF]. Either provide the CSRF Token or disable CSRF protection (not recommended).
 
 [[appendix-faq-no-security-on-forward]]
-==== I'm forwarding a request to another URL using the RequestDispatcher, but my security constraints aren't being applied.
+=== I'm forwarding a request to another URL using the RequestDispatcher, but my security constraints aren't being applied.
 
 Filters are not applied by default to forwards or includes.
 If you really want the security filters to be applied to forwards and/or includes, then you have to configure these explicitly in your web.xml using the <dispatcher> element, a child element of <filter-mapping>.
 
 
 [[appendix-faq-method-security-in-web-context]]
-==== I have added Spring Security's <global-method-security> element to my application context but if I add security annotations to my Spring MVC controller beans (Struts actions etc.) then they don't seem to have an effect.
+=== I have added Spring Security's <global-method-security> element to my application context but if I add security annotations to my Spring MVC controller beans (Struts actions etc.) then they don't seem to have an effect.
 
 In a Spring web application, the application context which holds the Spring MVC beans for the dispatcher servlet is often separate from the main application context.
 It is often defined in a file called `myapp-servlet.xml`, where "myapp" is the name assigned to the Spring `DispatcherServlet` in `web.xml`. An application can have multiple ``DispatcherServlet``s, each with its own isolated application context.
@@ -333,7 +333,7 @@ Generally we would recommend applying method security at the service layer rathe
 
 
 [[appendix-faq-no-filters-no-context]]
-==== I have a user who has definitely been authenticated, but when I try to access the SecurityContextHolder during some requests, the Authentication is null.
+=== I have a user who has definitely been authenticated, but when I try to access the SecurityContextHolder during some requests, the Authentication is null.
 Why can't I see the user information?
 
 If you have excluded the request from the security filter chain using the attribute `filters='none'` in the `<intercept-url>` element that matches the URL pattern, then the `SecurityContextHolder` will not be populated for that request.
@@ -341,12 +341,12 @@ Check the debug log to see whether the request is passing through the filter cha
 (You are reading the debug log, right?).
 
 [[appendix-faq-method-security-with-taglib]]
-==== The authorize JSP Tag doesn't respect my method security annotations when using the URL attribute.
+=== The authorize JSP Tag doesn't respect my method security annotations when using the URL attribute.
 
 Method security will not hide links when using the `url` attribute in `<sec:authorize>` because we cannot readily reverse engineer what URL is mapped to what controller endpoint as controllers can rely on headers, current user, etc to determine what method to invoke.
 
 [[appendix-faq-architecture]]
-=== Spring Security Architecture Questions
+== Spring Security Architecture Questions
 
 . <<appendix-faq-where-is-class-x>>
 . <<appendix-faq-namespace-to-bean-mapping>>
@@ -357,14 +357,14 @@ Method security will not hide links when using the `url` attribute in `<sec:auth
 
 
 [[appendix-faq-where-is-class-x]]
-==== How do I know which package class X is in?
+=== How do I know which package class X is in?
 
 The best way of locating classes is by installing the Spring Security source in your IDE. The distribution includes source jars for each of the modules the project is divided up into.
 Add these to your project source path and you can navigate directly to Spring Security classes (`Ctrl-Shift-T` in Eclipse). This also makes debugging easier and allows you to troubleshoot exceptions by looking directly at the code where they occur to see what's going on there.
 
 
 [[appendix-faq-namespace-to-bean-mapping]]
-==== How do the namespace elements map to conventional bean configurations?
+=== How do the namespace elements map to conventional bean configurations?
 
 There is a general overview of what beans are created by the namespace in the namespace appendix of the reference guide.
 There is also a detailed blog article called "Behind the Spring Security Namespace" on https://spring.io/blog/2010/03/06/behind-the-spring-security-namespace/[blog.springsource.com]. If want to know the full details then the code is in the `spring-security-config` module within the Spring Security 3.0 distribution.
@@ -372,7 +372,7 @@ You should probably read the chapters on namespace parsing in the standard Sprin
 
 
 [[appendix-faq-role-prefix]]
-==== What does "ROLE_" mean and why do I need it on my role names?
+=== What does "ROLE_" mean and why do I need it on my role names?
 
 Spring Security has a voter-based architecture which means that an access decision is made by a series of ``AccessDecisionVoter``s.
 The voters act on the "configuration attributes" which are specified for a secured resource (such as a method invocation). With this approach, not all attributes may be relevant to all voters and a voter needs to know when it should ignore an attribute (abstain) and when it should vote to grant or deny access based on the attribute value.
@@ -384,7 +384,7 @@ The prefix can be changed by setting the `rolePrefix` property of `RoleVoter`. I
 
 
 [[appendix-faq-what-dependencies]]
-==== How do I know which dependencies to add to my application to work with Spring Security?
+=== How do I know which dependencies to add to my application to work with Spring Security?
 
 It will depend on what features you are using and what type of application you are developing.
 With Spring Security 3.0, the project jars are divided into clearly distinct areas of functionality, so it is straightforward to work out which Spring Security jars you need from your application requirements.
@@ -403,7 +403,7 @@ Any which are marked as "optional" in the Spring Security POM files will have to
 
 
 [[appendix-faq-apacheds-deps]]
-==== What dependencies are needed to run an embedded ApacheDS LDAP server?
+=== What dependencies are needed to run an embedded ApacheDS LDAP server?
 
 If you are using Maven, you need to add the following to your pom dependencies:
 
@@ -428,7 +428,7 @@ If you are using Maven, you need to add the following to your pom dependencies:
 The other required jars should be pulled in transitively.
 
 [[appendix-faq-what-is-userdetailservice]]
-==== What is a UserDetailsService and do I need one?
+=== What is a UserDetailsService and do I need one?
 
 `UserDetailsService` is a DAO interface for loading data that is specific to a user account.
 It has no other function other to load that data for use by other components within the framework.
@@ -440,7 +440,7 @@ If you want to customize the authentication process then you should implement `A
 See this https://spring.io/blog/2010/08/02/spring-security-in-google-app-engine/[ blog article] for an example integrating Spring Security authentication with Google App Engine.
 
 [[appendix-faq-howto]]
-=== Common "Howto" Requests
+== Common "Howto" Requests
 
 . <<appendix-faq-extra-login-fields>>
 . <<appendix-faq-matching-url-fragments>>
@@ -453,7 +453,7 @@ See this https://spring.io/blog/2010/08/02/spring-security-in-google-app-engine/
 
 
 [[appendix-faq-extra-login-fields]]
-==== I need to login in with more information than just the username.
+=== I need to login in with more information than just the username.
 How do I add support for extra login fields (e.g.
 a company name)?
 
@@ -465,14 +465,14 @@ You will also need to customize the actual authentication process.
 If you are using a custom authentication token class, for example, you will have to write an `AuthenticationProvider` to handle it (or extend the standard `DaoAuthenticationProvider`). If you have concatenated the fields, you can implement your own `UserDetailsService` which splits them up and loads the appropriate user data for authentication.
 
 [[appendix-faq-matching-url-fragments]]
-==== How do I apply different intercept-url constraints where only the fragment value of the requested URLs differs (e.g./foo#bar and /foo#blah?
+=== How do I apply different intercept-url constraints where only the fragment value of the requested URLs differs (e.g./foo#bar and /foo#blah?
 
 You can't do this, since the fragment is not transmitted from the browser to the server.
 The URLs above are identical from the server's perspective.
 This is a common question from GWT users.
 
 [[appendix-faq-request-details-in-user-service]]
-==== How do I access the user's IP Address (or other web-request data) in a UserDetailsService?
+=== How do I access the user's IP Address (or other web-request data) in a UserDetailsService?
 
 Obviously you can't (without resorting to something like thread-local variables) since the only information supplied to the interface is the username.
 Instead of implementing `UserDetailsService`, you should implement `AuthenticationProvider` directly and extract the information from the supplied `Authentication` token.
@@ -482,7 +482,7 @@ If you are using the namespace, for example with the `<form-login>` element, the
 
 
 [[appendix-faq-access-session-from-user-service]]
-==== How do I access the HttpSession from a UserDetailsService?
+=== How do I access the HttpSession from a UserDetailsService?
 
 You can't, since the `UserDetailsService` has no awareness of the servlet API. If you want to store custom user data, then you should customize the `UserDetails` object which is returned.
 This can then be accessed at any point, via the thread-local `SecurityContextHolder`. A call to `SecurityContextHolder.getContext().getAuthentication().getPrincipal()` will return this custom object.
@@ -491,14 +491,14 @@ If you really need to access the session, then it must be done by customizing th
 
 
 [[appendix-faq-password-in-user-service]]
-==== How do I access the user's password in a UserDetailsService?
+=== How do I access the user's password in a UserDetailsService?
 
 You can't (and shouldn't). You are probably misunderstanding its purpose.
 See "<<appendix-faq-what-is-userdetailservice,What is a UserDetailsService?>>" above.
 
 
 [[appendix-faq-dynamic-url-metadata]]
-==== How do I define the secured URLs within an application dynamically?
+=== How do I define the secured URLs within an application dynamically?
 
 People often ask about how to store the mapping between secured URLs and security metadata attributes in a database, rather than in the application context.
 
@@ -575,7 +575,7 @@ For more information, look at the code for `DefaultFilterInvocationSecurityMetad
 
 
 [[appendix-faq-ldap-authorities]]
-==== How do I authenticate against LDAP but load user roles from a database?
+=== How do I authenticate against LDAP but load user roles from a database?
 
 The `LdapAuthenticationProvider` bean (which handles normal LDAP authentication in Spring Security) is configured with two separate strategy interfaces, one which performs the authentication and one which loads the user authorities, called `LdapAuthenticator` and `LdapAuthoritiesPopulator` respectively.
 The `DefaultLdapAuthoritiesPopulator` loads the user authorities from the LDAP directory and has various configuration parameters to allow you to specify how these should be retrieved.
@@ -637,7 +637,7 @@ You should also consult the Javadoc for the relevant classes and interfaces.
 
 
 [[appendix-faq-namespace-post-processor]]
-==== I want to modify the property of a bean that is created by the namespace, but there is nothing in the schema to support it.
+=== I want to modify the property of a bean that is created by the namespace, but there is nothing in the schema to support it.
 What can I do short of abandoning namespace use?
 
 The namespace functionality is intentionally limited, so it doesn't cover everything that you can do with plain beans.

File diff suppressed because it is too large
+ 130 - 130
docs/modules/ROOT/pages/servlet/appendix/namespace.adoc


+ 1 - 1
docs/modules/ROOT/pages/servlet/appendix/proxy-server.adoc

@@ -1,5 +1,5 @@
 [[appendix-proxy-server]]
-== Proxy Server Configuration
+= Proxy Server Configuration
 
 When using a proxy server it is important to ensure that you have configured your application properly.
 For example, many applications will have a load balancer that responds to request for https://example.com/ by forwarding the request to an application server at https://192.168.1:8080

+ 5 - 5
docs/modules/ROOT/pages/servlet/authentication/anonymous.adoc

@@ -1,9 +1,9 @@
 [[anonymous]]
-== Anonymous Authentication
+= Anonymous Authentication
 
 
 [[anonymous-overview]]
-=== Overview
+== Overview
 It's generally considered good security practice to adopt a "deny-by-default" where you explicitly specify what is allowed and disallow everything else.
 Defining what is accessible to unauthenticated users is a similar situation, particularly for web applications.
 Many sites require that users must be authenticated for anything other than a few URLs (for example the home and login pages).
@@ -21,7 +21,7 @@ Classes can be authored more robustly if they know the `SecurityContextHolder` a
 
 
 [[anonymous-config]]
-=== Configuration
+== Configuration
 Anonymous authentication support is provided automatically when using the HTTP configuration Spring Security 3.0 and can be customized (or disabled) using the `<anonymous>` element.
 You don't need to configure the beans described here unless you are using traditional bean configuration.
 
@@ -88,7 +88,7 @@ For example:
 
 
 [[anonymous-auth-trust-resolver]]
-=== AuthenticationTrustResolver
+== AuthenticationTrustResolver
 Rounding out the anonymous authentication discussion is the `AuthenticationTrustResolver` interface, with its corresponding `AuthenticationTrustResolverImpl` implementation.
 This interface provides an `isAnonymous(Authentication)` method, which allows interested classes to take into account this special type of authentication status.
 The `ExceptionTranslationFilter` uses this interface in processing ``AccessDeniedException``s.
@@ -102,7 +102,7 @@ The `AuthenticatedVoter` approach is more powerful, since it allows you to diffe
 If you don't need this functionality though, then you can stick with `ROLE_ANONYMOUS`, which will be processed by Spring Security's standard `RoleVoter`.
 
 [[anonymous-auth-mvc-controller]]
-=== Getting Anonymous Authentications with Spring MVC
+== Getting Anonymous Authentications with Spring MVC
 
 https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments[Spring MVC resolves parameters of type `Principal`] using its own argument resolver.
 

+ 11 - 11
docs/modules/ROOT/pages/servlet/authentication/cas.adoc

@@ -1,8 +1,8 @@
 [[servlet-cas]]
-== CAS Authentication
+= CAS Authentication
 
 [[cas-overview]]
-=== Overview
+== Overview
 JA-SIG produces an enterprise-wide single sign on system known as CAS.
 Unlike other initiatives, JA-SIG's Central Authentication Service is open source, widely used, simple to understand, platform independent, and supports proxy capabilities.
 Spring Security fully supports CAS, and provides an easy migration path from single-application deployments of Spring Security through to multiple-application deployments secured by an enterprise-wide CAS server.
@@ -11,7 +11,7 @@ You can learn more about CAS at https://www.apereo.org.
 You will also need to visit this site to download the CAS Server files.
 
 [[cas-how-it-works]]
-=== How CAS Works
+== How CAS Works
 Whilst the CAS web site contains documents that detail the architecture of CAS, we present the general overview again here within the context of Spring Security.
 Spring Security 3.x supports CAS 3.
 At the time of writing, the CAS server was at version 3.4.
@@ -34,7 +34,7 @@ Authenticating a proxy ticket differs because the list of proxies must be valida
 
 
 [[cas-sequence]]
-==== Spring Security and CAS Interaction Sequence
+=== Spring Security and CAS Interaction Sequence
 The basic interaction between a web browser, CAS server and a Spring Security-secured service is as follows:
 
 * The web user is browsing the service's public pages.
@@ -87,7 +87,7 @@ It's good that you're still here!
 Let's now look at how this is configured
 
 [[cas-client]]
-=== Configuration of CAS Client
+== Configuration of CAS Client
 The web application side of CAS is made easy due to Spring Security.
 It is assumed you already know the basics of using Spring Security, so these are not covered again below.
 We'll assume a namespace based configuration is being used and add in the CAS beans as required.
@@ -96,7 +96,7 @@ A full CAS sample application can be found in the Spring Security <<samples,Samp
 
 
 [[cas-st]]
-==== Service Ticket Authentication
+=== Service Ticket Authentication
 This section describes how to setup Spring Security to authenticate Service Tickets.
 Often times this is all a web application requires.
 You will need to add a `ServiceProperties` bean to your application context.
@@ -194,7 +194,7 @@ In the following sections we will discuss some (optional) more advanced configur
 
 
 [[cas-singlelogout]]
-==== Single Logout
+=== Single Logout
 The CAS protocol supports Single Logout and can be easily added to your Spring Security configuration.
 Below are updates to the Spring Security configuration that handle Single Logout
 
@@ -271,14 +271,14 @@ The `SingleSignOutHttpSessionListener` ensures that when an `HttpSession` expire
 
 
 [[cas-pt-client]]
-==== Authenticating to a Stateless Service with CAS
+=== Authenticating to a Stateless Service with CAS
 This section describes how to authenticate to a service using CAS.
 In other words, this section discusses how to setup a client that uses a service that authenticates with CAS.
 The next section describes how to setup a stateless service to Authenticate using CAS.
 
 
 [[cas-pt-client-config]]
-===== Configuring CAS to Obtain Proxy Granting Tickets
+==== Configuring CAS to Obtain Proxy Granting Tickets
 In order to authenticate to a stateless service, the application needs to obtain a proxy granting ticket (PGT).
 This section describes how to configure Spring Security to obtain a PGT building upon thencas-st[Service Ticket Authentication] configuration.
 
@@ -335,7 +335,7 @@ An example configuration is shown below.
 ----
 
 [[cas-pt-client-sample]]
-===== Calling a Stateless Service Using a Proxy Ticket
+==== Calling a Stateless Service Using a Proxy Ticket
 Now that Spring Security obtains PGTs, you can use them to create proxy tickets which can be used to authenticate to a stateless service.
 The CAS <<samples,sample application>> contains a working example in the `ProxyTicketSampleServlet`.
 Example code can be found below:
@@ -379,7 +379,7 @@ protected fun doGet(request: HttpServletRequest, response: HttpServletResponse?)
 ====
 
 [[cas-pt]]
-==== Proxy Ticket Authentication
+=== Proxy Ticket Authentication
 The `CasAuthenticationProvider` distinguishes between stateful and stateless clients.
 A stateful client is considered any that submits to the `filterProcessUrl` of the `CasAuthenticationFilter`.
 A stateless client is any that presents an authentication request to `CasAuthenticationFilter` on a URL other than the `filterProcessUrl`.

+ 3 - 3
docs/modules/ROOT/pages/servlet/authentication/events.adoc

@@ -1,5 +1,5 @@
 [[servlet-events]]
-== Authentication Events
+= Authentication Events
 
 For each authentication that succeeds or fails, a `AuthenticationSuccessEvent` or `AbstractAuthenticationFailureEvent` is fired, respectively.
 
@@ -68,7 +68,7 @@ class AuthenticationEvents {
 
 While similar to `AuthenticationSuccessHandler` and `AuthenticationFailureHandler`, these are nice in that they can be used independently from the servlet API.
 
-=== Adding Exception Mappings
+== Adding Exception Mappings
 
 `DefaultAuthenticationEventPublisher` by default will publish an `AbstractAuthenticationFailureEvent` for the following events:
 
@@ -121,7 +121,7 @@ fun authenticationEventPublisher
 ----
 ====
 
-=== Default Event
+== Default Event
 
 And, you can supply a catch-all event to fire in the case of any `AuthenticationException`:
 

+ 10 - 10
docs/modules/ROOT/pages/servlet/authentication/jaas.adoc

@@ -1,21 +1,21 @@
 [[servlet-jaas]]
-== Java Authentication and Authorization Service (JAAS) Provider
+= Java Authentication and Authorization Service (JAAS) Provider
 
 
-=== Overview
+== Overview
 Spring Security provides a package able to delegate authentication requests to the Java Authentication and Authorization Service (JAAS).
 This package is discussed in detail below.
 
 
 [[jaas-abstractjaasauthenticationprovider]]
-=== AbstractJaasAuthenticationProvider
+== AbstractJaasAuthenticationProvider
 The `AbstractJaasAuthenticationProvider` is the basis for the provided JAAS `AuthenticationProvider` implementations.
 Subclasses must implement a method that creates the `LoginContext`.
 The `AbstractJaasAuthenticationProvider` has a number of dependencies that can be injected into it that are discussed below.
 
 
 [[jaas-callbackhandler]]
-==== JAAS CallbackHandler
+=== JAAS CallbackHandler
 Most JAAS ``LoginModule``s require a callback of some sort.
 These callbacks are usually used to obtain the username and password from the user.
 
@@ -33,7 +33,7 @@ If the `LoginModule` requests a callback against the ``InternalCallbackHandler``
 
 
 [[jaas-authoritygranter]]
-==== JAAS AuthorityGranter
+=== JAAS AuthorityGranter
 JAAS works with principals.
 Even "roles" are represented as principals in JAAS.
 Spring Security, on the other hand, works with `Authentication` objects.
@@ -50,14 +50,14 @@ However, there is a `TestAuthorityGranter` in the unit tests that demonstrates a
 
 
 [[jaas-defaultjaasauthenticationprovider]]
-=== DefaultJaasAuthenticationProvider
+== DefaultJaasAuthenticationProvider
 The `DefaultJaasAuthenticationProvider` allows a JAAS `Configuration` object to be injected into it as a dependency.
 It then creates a `LoginContext` using the injected JAAS `Configuration`.
 This means that `DefaultJaasAuthenticationProvider` is not bound any particular implementation of `Configuration` as `JaasAuthenticationProvider` is.
 
 
 [[jaas-inmemoryconfiguration]]
-==== InMemoryConfiguration
+=== InMemoryConfiguration
 In order to make it easy to inject a `Configuration` into `DefaultJaasAuthenticationProvider`, a default in-memory implementation named `InMemoryConfiguration` is provided.
 The implementation constructor accepts a `Map` where each key represents a login configuration name and the value represents an `Array` of ``AppConfigurationEntry``s.
 `InMemoryConfiguration` also supports a default `Array` of `AppConfigurationEntry` objects that will be used if no mapping is found within the provided `Map`.
@@ -65,7 +65,7 @@ For details, refer to the class level javadoc of `InMemoryConfiguration`.
 
 
 [[jaas-djap-config]]
-==== DefaultJaasAuthenticationProvider Example Configuration
+=== DefaultJaasAuthenticationProvider Example Configuration
 While the Spring configuration for `InMemoryConfiguration` can be more verbose than the standard JAAS configuration files, using it in conjunction with `DefaultJaasAuthenticationProvider` is more flexible than `JaasAuthenticationProvider` since it not dependant on the default `Configuration` implementation.
 
 An example configuration of `DefaultJaasAuthenticationProvider` using `InMemoryConfiguration` is provided below.
@@ -116,7 +116,7 @@ class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticatio
 
 
 [[jaas-jaasauthenticationprovider]]
-=== JaasAuthenticationProvider
+== JaasAuthenticationProvider
 The `JaasAuthenticationProvider` assumes the default `Configuration` is an instance of https://docs.oracle.com/javase/8/docs/jre/api/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html[ ConfigFile].
 This assumption is made in order to attempt to update the `Configuration`.
 The `JaasAuthenticationProvider` then uses the default `Configuration` to create the `LoginContext`.
@@ -157,7 +157,7 @@ class="org.springframework.security.authentication.jaas.JaasAuthenticationProvid
 ----
 
 [[jaas-apiprovision]]
-=== Running as a Subject
+== Running as a Subject
 If configured, the `JaasApiIntegrationFilter` will attempt to run as the `Subject` on the `JaasAuthenticationToken`.
 This means that the `Subject` can be accessed using:
 

+ 6 - 6
docs/modules/ROOT/pages/servlet/authentication/logout.adoc

@@ -1,8 +1,8 @@
 [[jc-logout]]
-== Handling Logouts
+= Handling Logouts
 
 [[logout-java-configuration]]
-=== Logout Java/Kotlin Configuration
+== Logout Java/Kotlin Configuration
 
 When using the `{security-api-url}org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.html[WebSecurityConfigurerAdapter]`, logout capabilities are automatically applied.
 The default is that accessing the URL `/logout` will log the user out by:
@@ -86,13 +86,13 @@ For many common scenarios, these handlers are applied under the
 covers when using the fluent API.
 
 [[ns-logout]]
-=== Logout XML Configuration
+== Logout XML Configuration
 The `logout` element adds support for logging out by navigating to a particular URL.
 The default logout URL is `/logout`, but you can set it to something else using the `logout-url` attribute.
 More information on other available attributes may be found in the namespace appendix.
 
 [[jc-logout-handler]]
-=== LogoutHandler
+== LogoutHandler
 
 Generally, `{security-api-url}org/springframework/security/web/authentication/logout/LogoutHandler.html[LogoutHandler]`
 implementations indicate classes that are able to participate in logout handling.
@@ -115,7 +115,7 @@ E.g. `deleteCookies()` allows specifying the names of one or more cookies to be
 This is a shortcut compared to adding a `CookieClearingLogoutHandler`.
 
 [[jc-logout-success-handler]]
-=== LogoutSuccessHandler
+== LogoutSuccessHandler
 
 The `LogoutSuccessHandler` is called after a successful logout by the `LogoutFilter`, to handle e.g.
 redirection or forwarding to the appropriate destination.
@@ -137,7 +137,7 @@ Instead of redirecting to a URL upon the successful logout, this `LogoutSuccessH
 If not configured a status code 200 will be returned by default.
 
 [[jc-logout-references]]
-=== Further Logout-Related References
+== Further Logout-Related References
 
 - <<ns-logout, Logout Handling>>
 - <<test-logout, Testing Logout>>

+ 2 - 2
docs/modules/ROOT/pages/servlet/authentication/openid.adoc

@@ -1,5 +1,5 @@
 [[servlet-openid]]
-== OpenID Support
+= OpenID Support
 
 [NOTE]
 The OpenID 1.0 and 2.0 protocols have been deprecated and users are encouraged to migrate to OpenID Connect, which is supported by spring-security-oauth2.
@@ -27,7 +27,7 @@ Note that we have omitted the password attribute from the above user configurati
 A random password will be generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration.
 
 
-=== Attribute Exchange
+== Attribute Exchange
 Support for OpenID https://openid.net/specs/openid-attribute-exchange-1_0.html[attribute exchange].
 As an example, the following configuration would attempt to retrieve the email and full name from the OpenID provider, for use by the application:
 

+ 10 - 10
docs/modules/ROOT/pages/servlet/authentication/preauth.adoc

@@ -1,5 +1,5 @@
 [[servlet-preauth]]
-== Pre-Authentication Scenarios
+= Pre-Authentication Scenarios
 There are situations where you want to use Spring Security for authorization, but the user has already been reliably authenticated by some external system prior to accessing the application.
 We refer to these situations as "pre-authenticated" scenarios.
 Examples include X.509, Siteminder and authentication by the Java EE container in which the application is running.
@@ -16,7 +16,7 @@ If relying on container authentication, the user will be identified by calling t
 In some cases, the external mechanism may supply role/authority information for the user but in others the authorities must be obtained from a separate source, such as a `UserDetailsService`.
 
 
-=== Pre-Authentication Framework Classes
+== Pre-Authentication Framework Classes
 Because most pre-authentication mechanisms follow the same pattern, Spring Security has a set of classes which provide an internal framework for implementing pre-authenticated authentication providers.
 This removes duplication and allows new implementations to be added in a structured fashion, without having to write everything from scratch.
 You don't need to know about these classes if you want to use something like <<servlet-x509,X.509 authentication>>, as it already has a namespace configuration option which is simpler to use and get started with.
@@ -25,7 +25,7 @@ You will find classes under the `org.springframework.security.web.authentication
 We just provide an outline here so you should consult the Javadoc and source where appropriate.
 
 
-==== AbstractPreAuthenticatedProcessingFilter
+=== AbstractPreAuthenticatedProcessingFilter
 This class will check the current contents of the security context and, if empty, it will attempt to extract user information from the HTTP request and submit it to the `AuthenticationManager`.
 Subclasses override the following methods to obtain this information:
 
@@ -59,7 +59,7 @@ We'll look at a concrete example next.
 
 
 [[j2ee-preauth-details]]
-===== J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
+==== J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
 If the filter is configured with an `authenticationDetailsSource` which is an instance of this class, the authority information is obtained by calling the `isUserInRole(String role)` method for each of a pre-determined set of "mappable roles".
 The class gets these from a configured `MappableAttributesRetriever`.
 Possible implementations include hard-coding a list in the application context and reading the role information from the `<security-role>` information in a `web.xml` file.
@@ -69,7 +69,7 @@ There is an additional stage where the roles (or attributes) are mapped to Sprin
 The default will just add the usual `ROLE_` prefix to the names, but it gives you full control over the behaviour.
 
 
-==== PreAuthenticatedAuthenticationProvider
+=== PreAuthenticatedAuthenticationProvider
 The pre-authenticated provider has little more to do than load the `UserDetails` object for the user.
 It does this by delegating to an `AuthenticationUserDetailsService`.
 The latter is similar to the standard `UserDetailsService` but takes an `Authentication` object rather than just user name:
@@ -85,19 +85,19 @@ This interface may have also other uses but with pre-authentication it allows ac
 The `PreAuthenticatedGrantedAuthoritiesUserDetailsService` class does this.
 Alternatively, it may delegate to a standard `UserDetailsService` via the `UserDetailsByNameServiceWrapper` implementation.
 
-==== Http403ForbiddenEntryPoint
+=== Http403ForbiddenEntryPoint
 The <<servlet-authentication-authenticationentrypoint,`AuthenticationEntryPoint`>> is responsible for kick-starting the authentication process for an unauthenticated user (when they try to access a protected resource), but in the pre-authenticated case this doesn't apply.
 You would only configure the `ExceptionTranslationFilter` with an instance of this class if you aren't using pre-authentication in combination with other authentication mechanisms.
 It will be called if the user is rejected by the `AbstractPreAuthenticatedProcessingFilter` resulting in a null authentication.
 It always returns a `403`-forbidden response code if called.
 
 
-=== Concrete Implementations
+== Concrete Implementations
 X.509 authentication is covered in its <<servlet-x509,own chapter>>.
 Here we'll look at some classes which provide support for other pre-authenticated scenarios.
 
 
-==== Request-Header Authentication (Siteminder)
+=== Request-Header Authentication (Siteminder)
 An external authentication system may supply information to the application by setting specific headers on the HTTP request.
 A well-known example of this is Siteminder, which passes the username in a header called `SM_USER`.
 This mechanism is supported by the class `RequestHeaderAuthenticationFilter` which simply extracts the username from the header.
@@ -110,7 +110,7 @@ Note that when using a system like this, the framework performs no authenticatio
 If an attacker is able to forge the headers in their original request without this being detected then they could potentially choose any username they wished.
 ====
 
-===== Siteminder Example Configuration
+==== Siteminder Example Configuration
 A typical configuration using this filter would look like this:
 
 [source,xml]
@@ -143,7 +143,7 @@ We've assumed here that the <<ns-config,security namespace>> is being used for c
 It's also assumed that you have added a `UserDetailsService` (called "userDetailsService") to your configuration to load the user's roles.
 
 
-==== Java EE Container Authentication
+=== Java EE Container Authentication
 The class `J2eePreAuthenticatedProcessingFilter` will extract the username from the `userPrincipal` property of the `HttpServletRequest`.
 Use of this filter would usually be combined with the use of Java EE roles as described above in <<j2ee-preauth-details>>.
 

+ 7 - 7
docs/modules/ROOT/pages/servlet/authentication/rememberme.adoc

@@ -1,9 +1,9 @@
 [[servlet-rememberme]]
-== Remember-Me Authentication
+= Remember-Me Authentication
 
 
 [[remember-me-overview]]
-=== Overview
+== Overview
 Remember-me or persistent-login authentication refers to web sites being able to remember the identity of a principal between sessions.
 This is typically accomplished by sending a cookie to the browser, with the cookie being detected during future sessions and causing automated login to take place.
 Spring Security provides the necessary hooks for these operations to take place, and has two concrete remember-me implementations.
@@ -14,7 +14,7 @@ If you are using an authentication provider which doesn't use a `UserDetailsServ
 
 
 [[remember-me-hash-token]]
-=== Simple Hash-Based Token Approach
+== Simple Hash-Based Token Approach
 This approach uses hashing to achieve a useful remember-me strategy.
 In essence a cookie is sent to the browser upon successful interactive authentication, with the cookie being composed as follows:
 
@@ -50,7 +50,7 @@ The `UserDetailsService` will normally be selected automatically.
 If you have more than one in your application context, you need to specify which one should be used with the `user-service-ref` attribute, where the value is the name of your `UserDetailsService` bean.
 
 [[remember-me-persistent-token]]
-=== Persistent Token Approach
+== Persistent Token Approach
 This approach is based on the article https://web.archive.org/web/20180819014446/http://jaspan.com/improved_persistent_login_cookie_best_practice[http://jaspan.com/improved_persistent_login_cookie_best_practice] with some minor modifications  footnote:[Essentially, the username is not included in the cookie, to prevent exposing a valid login name unecessarily.
 There is a discussion on this in the comments section of this article.].
 To use the this approach with namespace configuration, you would supply a datasource reference:
@@ -74,7 +74,7 @@ create table persistent_logins (username varchar(64) not null,
 ----
 
 [[remember-me-impls]]
-=== Remember-Me Interfaces and Implementations
+== Remember-Me Interfaces and Implementations
 Remember-me is used with `UsernamePasswordAuthenticationFilter`, and is implemented via hooks in the `AbstractAuthenticationProcessingFilter` superclass.
 It is also used within `BasicAuthenticationFilter`.
 The hooks will invoke a concrete `RememberMeServices` at the appropriate times.
@@ -97,7 +97,7 @@ This design allows any number of remember-me implementation strategies.
 We've seen above that Spring Security provides two implementations.
 We'll look at these in turn.
 
-==== TokenBasedRememberMeServices
+=== TokenBasedRememberMeServices
 This implementation supports the simpler approach described in <<remember-me-hash-token>>.
 `TokenBasedRememberMeServices` generates a `RememberMeAuthenticationToken`, which is processed by `RememberMeAuthenticationProvider`.
 A `key` is shared between this authentication provider and the `TokenBasedRememberMeServices`.
@@ -130,7 +130,7 @@ The beans required in an application context to enable remember-me services are
 Don't forget to add your `RememberMeServices` implementation to your `UsernamePasswordAuthenticationFilter.setRememberMeServices()` property, include the `RememberMeAuthenticationProvider` in your `AuthenticationManager.setProviders()` list, and add `RememberMeAuthenticationFilter` into your `FilterChainProxy` (typically immediately after your `UsernamePasswordAuthenticationFilter`).
 
 
-==== PersistentTokenBasedRememberMeServices
+=== PersistentTokenBasedRememberMeServices
 This class can be used in the same way as `TokenBasedRememberMeServices`, but it additionally needs to be configured with a `PersistentTokenRepository` to store the tokens.
 There are two standard implementations.
 

+ 3 - 3
docs/modules/ROOT/pages/servlet/authentication/runas.adoc

@@ -1,8 +1,8 @@
 [[runas]]
-== Run-As Authentication Replacement
+= Run-As Authentication Replacement
 
 [[runas-overview]]
-=== Overview
+== Overview
 The `AbstractSecurityInterceptor` is able to temporarily replace the `Authentication` object in the `SecurityContext` and `SecurityContextHolder` during the secure object callback phase.
 This only occurs if the original `Authentication` object was successfully processed by the `AuthenticationManager` and `AccessDecisionManager`.
 The `RunAsManager` will indicate the replacement `Authentication` object, if any, that should be used during the `SecurityInterceptorCallback`.
@@ -12,7 +12,7 @@ It will also be able to perform any internal security checks for specific `Grant
 Because Spring Security provides a number of helper classes that automatically configure remoting protocols based on the contents of the `SecurityContextHolder`, these run-as replacements are particularly useful when calling remote web services.
 
 [[runas-config]]
-=== Configuration
+== Configuration
 A `RunAsManager` interface is provided by Spring Security:
 
 [source,java]

+ 8 - 8
docs/modules/ROOT/pages/servlet/authentication/session-management.adoc

@@ -1,9 +1,9 @@
 [[session-mgmt]]
-== Session Management
+= Session Management
 HTTP session related functionality is handled by a combination of the `SessionManagementFilter` and the `SessionAuthenticationStrategy` interface, which the filter delegates to.
 Typical usage includes session-fixation protection attack prevention, detection of session timeouts and restrictions on how many sessions an authenticated user may have open concurrently.
 
-=== Detecting Timeouts
+== Detecting Timeouts
 You can configure Spring Security to detect the submission of an invalid session ID and redirect the user to an appropriate URL.
 This is achieved through the `session-management` element:
 
@@ -74,7 +74,7 @@ Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 197
 
 
 [[ns-concurrent-sessions]]
-=== Concurrent Session Control
+== Concurrent Session Control
 If you wish to place constraints on a single user's ability to log in to your application, Spring Security supports this out of the box with the following simple additions.
 First, you need to add the following listener to your configuration to keep Spring Security updated about session lifecycle events:
 
@@ -165,7 +165,7 @@ If you are using a customized authentication filter for form-based login, then y
 More details can be found in the <<session-mgmt,Session Management chapter>>.
 
 [[ns-session-fixation]]
-=== Session Fixation Attack Protection
+== Session Fixation Attack Protection
 https://en.wikipedia.org/wiki/Session_fixation[Session fixation] attacks are a potential risk where it is possible for a malicious attacker to create a session by accessing a site, then persuade another user to log in with the same session (by sending them a link containing the session identifier as a parameter, for example).
 Spring Security protects against this automatically by creating a new session or otherwise changing the session ID when a user logs in.
 If you don't require this protection, or it conflicts with some other requirement, you can control the behavior using the `session-fixation-protection` attribute on `<session-management>`, which has four options
@@ -189,7 +189,7 @@ When session fixation protection occurs, it results in a `SessionFixationProtect
 If you use `changeSessionId`, this protection will __also__ result in any  ``javax.servlet.http.HttpSessionIdListener``s being notified, so use caution if your code listens for both events.
 See the <<session-mgmt,Session Management>> chapter for additional information.
 
-=== SessionManagementFilter
+== SessionManagementFilter
 The `SessionManagementFilter` checks the contents of the `SecurityContextRepository` against the current contents of the `SecurityContextHolder` to determine whether a user has been authenticated during the current request, typically by a non-interactive authentication mechanism, such as pre-authentication or remember-me  footnote:[
 Authentication by mechanisms which perform a redirect after authenticating (such as form-login) will not be detected by `SessionManagementFilter`, as the filter will not be invoked during the authenticating request.
 Session-management functionality has to be handled separately in these cases.
@@ -203,7 +203,7 @@ The most common behaviour is just to redirect to a fixed URL and this is encapsu
 The latter is also used when configuring an invalid session URL through the namespace, <<session-mgmt,as described earlier>>.
 
 
-=== SessionAuthenticationStrategy
+== SessionAuthenticationStrategy
 `SessionAuthenticationStrategy` is used by both `SessionManagementFilter` and `AbstractAuthenticationProcessingFilter`, so if you are using a customized form-login class, for example, you will need to inject it into both of these.
 In this case, a typical configuration, combining the namespace and custom beans might look like this:
 
@@ -230,7 +230,7 @@ Note that the use of the default, `SessionFixationProtectionStrategy` may cause
 See the Javadoc for this class for more information.
 
 [[concurrent-sessions]]
-=== Concurrency Control
+== Concurrency Control
 Spring Security is able to prevent a principal from concurrently authenticating to the same application more than a specified number of times.
 Many ISVs take advantage of this to enforce licensing, whilst network administrators like this feature because it helps prevent people from sharing login names.
 You can, for example, stop user "Batman" from logging onto the web application from two different sessions.
@@ -327,7 +327,7 @@ Without it, a user will never be able to log back in again once they have exceed
 
 
 [[list-authenticated-principals]]
-==== Querying the SessionRegistry for currently authenticated users and their sessions
+=== Querying the SessionRegistry for currently authenticated users and their sessions
 Setting up concurrency-control, either through the namespace or using plain beans has the useful side effect of providing you with a reference to the `SessionRegistry` which you can use directly within your application, so even if you don't want to restrict the number of sessions a user may have, it may be worth setting up the infrastructure anyway.
 You can set the `maximumSession` property to -1 to allow unlimited sessions.
 If you're using the namespace, you can set an alias for the internally-created `SessionRegistry` using the `session-registry-alias` attribute, providing a reference which you can inject into your own beans.

+ 4 - 4
docs/modules/ROOT/pages/servlet/authentication/x509.adoc

@@ -1,9 +1,9 @@
 [[servlet-x509]]
-== X.509 Authentication
+= X.509 Authentication
 
 
 [[x509-overview]]
-=== Overview
+== Overview
 The most common use of X.509 certificate authentication is in verifying the identity of a server when using SSL, most commonly when using HTTPS from a browser.
 The browser will automatically check that the certificate presented by a server has been issued (ie digitally signed) by one of a list of trusted certificate authorities which it maintains.
 
@@ -19,7 +19,7 @@ For example, if you're using Tomcat then read the instructions here https://tomc
 It's important that you get this working before trying it out with Spring Security
 
 
-=== Adding X.509 Authentication to Your Web Application
+== Adding X.509 Authentication to Your Web Application
 Enabling X.509 client authentication is very straightforward.
 Just add the `<x509/>` element to your http security namespace configuration.
 
@@ -51,7 +51,7 @@ If no certificate is found, or no corresponding user could be found then the sec
 This means that you can easily use X.509 authentication with other options such as a form-based login.
 
 [[x509-ssl-config]]
-=== Setting up SSL in Tomcat
+== Setting up SSL in Tomcat
 There are some pre-generated certificates in the {gh-samples-url}/servlet/java-configuration/authentication/x509/server[Spring Security Samples repository].
 You can use these to enable SSL for testing if you don't want to generate your own.
 The file `server.jks` contains the server certificate, private key and the issuing certificate authority certificate.

+ 4 - 4
docs/modules/ROOT/pages/servlet/authorization/acls.adoc

@@ -1,8 +1,8 @@
 [[domain-acls]]
-== Domain Object Security (ACLs)
+= Domain Object Security (ACLs)
 
 [[domain-acls-overview]]
-=== Overview
+== Overview
 Complex applications often will find the need to define access permissions not simply at a web request or method invocation level.
 Instead, security decisions need to comprise both who (`Authentication`), where (`MethodInvocation`) and what (`SomeDomainObject`).
 In other words, authorization decisions also need to consider the actual domain object instance subject of a method invocation.
@@ -37,7 +37,7 @@ Fortunately, there is another alternative, which we'll talk about below.
 
 
 [[domain-acls-key-concepts]]
-=== Key Concepts
+== Key Concepts
 Spring Security's ACL services are shipped in the `spring-security-acl-xxx.jar`.
 You will need to add this JAR to your classpath to use Spring Security's domain object instance security capabilities.
 
@@ -130,7 +130,7 @@ We suggest taking a look over these for examples.
 
 
 [[domain-acls-getting-started]]
-=== Getting Started
+== Getting Started
 To get starting using Spring Security's ACL capability, you will need to store your ACL information somewhere.
 This necessitates the instantiation of a `DataSource` using Spring.
 The `DataSource` is then injected into a `JdbcMutableAclService` and `BasicLookupStrategy` instance.

+ 13 - 13
docs/modules/ROOT/pages/servlet/authorization/expression-based.adoc

@@ -1,18 +1,18 @@
 
 [[el-access]]
-== Expression-Based Access Control
+= Expression-Based Access Control
 Spring Security 3.0 introduced the ability to use Spring EL expressions as an authorization mechanism in addition to the simple use of configuration attributes and access-decision voters which have been seen before.
 Expression-based access control is built on the same architecture but allows complicated Boolean logic to be encapsulated in a single expression.
 
 
-=== Overview
+== Overview
 Spring Security uses Spring EL for expression support and you should look at how that works if you are interested in understanding the topic in more depth.
 Expressions are evaluated with a "root object" as part of the evaluation context.
 Spring Security uses specific classes for web and method security as the root object, in order to provide built-in expressions and access to values such as the current principal.
 
 
 [[el-common-built-in]]
-==== Common Built-In Expressions
+=== Common Built-In Expressions
 The base class for expression root objects is `SecurityExpressionRoot`.
 This provides some common expressions which are available in both web and method security.
 
@@ -83,7 +83,7 @@ For example, `hasPermission(1, 'com.example.domain.Message', 'read')`
 
 
 [[el-access-web]]
-=== Web Security Expressions
+== Web Security Expressions
 To use expressions to secure individual URLs, you would first need to set the `use-expressions` attribute in the `<http>` element to `true`.
 Spring Security will then expect the `access` attributes of the `<intercept-url>` elements to contain Spring EL expressions.
 The expressions should evaluate to a Boolean, defining whether access should be allowed or not.
@@ -109,7 +109,7 @@ If expressions are being used, a `WebExpressionVoter` will be added to the `Acce
 So if you aren't using the namespace and want to use expressions, you will have to add one of these to your configuration.
 
 [[el-access-web-beans]]
-==== Referring to Beans in Web Security Expressions
+=== Referring to Beans in Web Security Expressions
 
 If you wish to extend the expressions that are available, you can easily refer to any Spring Bean you expose.
 For example, assuming you have a Bean with the name of `webSecurity` that contains the following method signature:
@@ -172,7 +172,7 @@ http {
 ====
 
 [[el-access-web-path-variables]]
-==== Path Variables in Web Security Expressions
+=== Path Variables in Web Security Expressions
 
 At times it is nice to be able to refer to path variables within a URL.
 For example, consider a RESTful application that looks up a user by id from the URL path in the format `+/user/{userId}+`.
@@ -240,13 +240,13 @@ http {
 In this configuration URLs that match would pass in the path variable (and convert it) into checkUserId method.
 For example, if the URL were `/user/123/resource`, then the id passed in would be `123`.
 
-=== Method Security Expressions
+== Method Security Expressions
 Method security is a bit more complicated than a simple allow or deny rule.
 Spring Security 3.0 introduced some new annotations in order to allow comprehensive support for the use of expressions.
 
 
 [[el-pre-post-annotations]]
-==== @Pre and @Post Annotations
+=== @Pre and @Post Annotations
 There are four annotations which support expression attributes to allow pre and post-invocation authorization checks and also to support filtering of submitted collection arguments or return values.
 They are `@PreAuthorize`, `@PreFilter`, `@PostAuthorize` and `@PostFilter`.
 Their use is enabled through the `global-method-security` namespace element:
@@ -256,7 +256,7 @@ Their use is enabled through the `global-method-security` namespace element:
 <global-method-security pre-post-annotations="enabled"/>
 ----
 
-===== Access Control using @PreAuthorize and @PostAuthorize
+==== Access Control using @PreAuthorize and @PostAuthorize
 The most obviously useful annotation is `@PreAuthorize` which decides whether a method can actually be invoked or not.
 For example (from the {gh-samples-url}/servlet/xml/java/contacts[Contacts] sample application)
 
@@ -412,7 +412,7 @@ This can be achieved using the `@PostAuthorize` annotation.
 To access the return value from a method, use the built-in name `returnObject` in the expression.
 --
 
-===== Filtering using @PreFilter and @PostFilter
+==== Filtering using @PreFilter and @PostFilter
 Spring Security supports filtering of collections, arrays, maps and streams using expressions.
 This is most commonly performed on the return value of a method.
 For example:
@@ -447,13 +447,13 @@ If you are filtering large collections and removing many of the entries then thi
 
 
 [[el-method-built-in]]
-==== Built-In Expressions
+=== Built-In Expressions
 There are some built-in expressions which are specific to method security, which we have already seen in use above.
 The `filterTarget` and `returnValue` values are simple enough, but the use of the `hasPermission()` expression warrants a closer look.
 
 
 [[el-permission-evaluator]]
-===== The PermissionEvaluator interface
+==== The PermissionEvaluator interface
 `hasPermission()` expressions are delegated to an instance of `PermissionEvaluator`.
 It is intended to bridge between the expression system and Spring Security's ACL system, allowing you to specify authorization constraints on domain objects, based on abstract permissions.
 It has no explicit dependencies on the ACL module, so you could swap that out for an alternative implementation if required.
@@ -494,7 +494,7 @@ Where `myPermissionEvaluator` is the bean which implements `PermissionEvaluator`
 Usually this will be the implementation from the ACL module which is called `AclPermissionEvaluator`.
 See the {gh-samples-url}/servlet/xml/java/contacts[Contacts] sample application configuration for more details.
 
-===== Method Security Meta Annotations
+==== Method Security Meta Annotations
 
 You can make use of meta annotations for method security to make your code more readable.
 This is especially convenient if you find that you are repeating the same complex expression throughout your code base.

+ 8 - 8
docs/modules/ROOT/pages/servlet/authorization/method-security.adoc

@@ -1,12 +1,12 @@
 [[jc-method]]
-== Method Security
+= Method Security
 
 From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods.
 It provides support for JSR-250 annotation security as well as the framework's original `@Secured` annotation.
 From 3.0 you can also make use of new <<el-access,expression-based annotations>>.
 You can apply security to a single bean, using the `intercept-methods` element to decorate the bean declaration, or you can secure multiple beans across the entire service layer using the AspectJ style pointcuts.
 
-=== EnableMethodSecurity
+== EnableMethodSecurity
 
 In Spring Security 5.6, we can enable annotation-based security using the `@EnableMethodSecurity` annotation on any `@Configuration` instance.
 
@@ -149,7 +149,7 @@ class MethodSecurityConfig {
 ----
 ====
 
-==== Customizing Authorization
+=== Customizing Authorization
 
 Spring Security's `@PreAuthorize`, `@PostAuthorize`, `@PreFilter`, and `@PostFilter` ship with rich expression-based support.
 
@@ -245,7 +245,7 @@ We expose `GrantedAuthorityDefaults` using a `static` method to ensure that Spri
 ====
 
 [[jc-method-security-custom-authorization-manager]]
-==== Custom Authorization Managers
+=== Custom Authorization Managers
 
 Method authorization is a combination of before- and after-method authorization.
 
@@ -598,7 +598,7 @@ class MethodSecurityConfig {
 and it will be invoked after the `@PostAuthorize` interceptor.
 
 [[jc-enable-global-method-security]]
-=== EnableGlobalMethodSecurity
+== EnableGlobalMethodSecurity
 
 We can enable annotation-based security using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance.
 For example, the following would enable Spring Security's `@Secured` annotation.
@@ -740,7 +740,7 @@ interface BankService {
 ----
 ====
 
-=== GlobalMethodSecurityConfiguration
+== GlobalMethodSecurityConfiguration
 
 Sometimes you may need to perform operations that are more complicated than are possible with the `@EnableGlobalMethodSecurity` annotation allow.
 For these instances, you can extend the `GlobalMethodSecurityConfiguration` ensuring that the `@EnableGlobalMethodSecurity` annotation is present on your subclass.
@@ -776,7 +776,7 @@ open class MethodSecurityConfig : GlobalMethodSecurityConfiguration() {
 For additional information about methods that can be overridden, refer to the `GlobalMethodSecurityConfiguration` Javadoc.
 
 [[ns-global-method]]
-=== The <global-method-security> Element
+== The <global-method-security> Element
 This element is used to enable annotation-based security in your application (by setting the appropriate attributes on the element), and also to group together security pointcut declarations which will be applied across your entire application context.
 You should only declare one `<global-method-security>` element.
 The following declaration would enable support for Spring Security's `@Secured`:
@@ -889,7 +889,7 @@ If two annotations are found which apply to a particular method, then only one o
 ====
 
 [[ns-protect-pointcut]]
-=== Adding Security Pointcuts using protect-pointcut
+== Adding Security Pointcuts using protect-pointcut
 
 The use of `protect-pointcut` is particularly powerful, as it allows you to apply security to many beans with only a simple declaration.
 Consider the following example:

+ 4 - 4
docs/modules/ROOT/pages/servlet/authorization/secure-objects.adoc

@@ -1,9 +1,9 @@
 
 [[secure-object-impls]]
-== Secure Object Implementations
+= Secure Object Implementations
 
 [[aop-alliance]]
-=== AOP Alliance (MethodInvocation) Security Interceptor
+== AOP Alliance (MethodInvocation) Security Interceptor
 Prior to Spring Security 2.0, securing ``MethodInvocation``s needed quite a lot of boiler plate configuration.
 Now the recommended approach for method security is to use <<ns-method-security,namespace configuration>>.
 This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes.
@@ -15,7 +15,7 @@ The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the con
 `MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and will be used internally when the attributes are defined in the application context using the `<intercept-methods>` or `<protect-point>` elements.
 Other implementations will be used to handle annotation-based configuration.
 
-==== Explicit MethodSecurityInterceptor Configuration
+=== Explicit MethodSecurityInterceptor Configuration
 You can of course configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms:
 
 [source,xml]
@@ -36,7 +36,7 @@ You can of course configure a `MethodSecurityInterceptor` directly in your appli
 ----
 
 [[aspectj]]
-=== AspectJ (JoinPoint) Security Interceptor
+== AspectJ (JoinPoint) Security Interceptor
 The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section.
 Indeed we will only discuss the differences in this section.
 

+ 4 - 4
docs/modules/ROOT/pages/servlet/integrations/concurrency.adoc

@@ -1,5 +1,5 @@
 [[concurrency]]
-== Concurrency Support
+= Concurrency Support
 
 In most environments, Security is stored on a per `Thread` basis.
 This means that when work is done on a new `Thread`, the `SecurityContext` is lost.
@@ -7,7 +7,7 @@ Spring Security provides some infrastructure to help make this much easier for u
 Spring Security provides low level abstractions for working with Spring Security in multi-threaded environments.
 In fact, this is what Spring Security builds on to integration with <<servletapi-start-runnable>> and <<mvc-async>>.
 
-=== DelegatingSecurityContextRunnable
+== DelegatingSecurityContextRunnable
 
 One of the most fundamental building blocks within Spring Security's concurrency support is the `DelegatingSecurityContextRunnable`.
 It wraps a delegate `Runnable` in order to initialize the `SecurityContextHolder` with a specified `SecurityContext` for the delegate.
@@ -122,7 +122,7 @@ Thread(wrappedRunnable).start()
 The code we have is simple to use, but it still requires knowledge that we are using Spring Security.
 In the next section we will take a look at how we can utilize `DelegatingSecurityContextExecutor` to hide the fact that we are using Spring Security.
 
-=== DelegatingSecurityContextExecutor
+== DelegatingSecurityContextExecutor
 
 In the previous section we found that it was easy to use the `DelegatingSecurityContextRunnable`, but it was not ideal since we had to be aware of Spring Security in order to use it.
 Let's take a look at how `DelegatingSecurityContextExecutor` can shield our code from any knowledge that we are using Spring Security.
@@ -244,7 +244,7 @@ val executor = DelegatingSecurityContextExecutor(delegateExecutor)
 Now anytime `executor.execute(Runnable)` is executed the `SecurityContext` is first obtained by the `SecurityContextHolder` and then that `SecurityContext` is used to create our `DelegatingSecurityContextRunnable`.
 This means that we are running our `Runnable` with the same user that was used to invoke the `executor.execute(Runnable)` code.
 
-=== Spring Security Concurrency Classes
+== Spring Security Concurrency Classes
 
 Refer to the Javadoc for additional integrations with both the Java concurrent APIs and the Spring Task abstractions.
 They are quite self-explanatory once you understand the previous code.

+ 1 - 1
docs/modules/ROOT/pages/servlet/integrations/cors.adoc

@@ -1,5 +1,5 @@
 [[cors]]
-== CORS
+= CORS
 
 Spring Framework provides https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors[first class support for CORS].
 CORS must be processed before Spring Security because the pre-flight request will not contain any cookies (i.e. the `JSESSIONID`).

+ 3 - 3
docs/modules/ROOT/pages/servlet/integrations/data.adoc

@@ -1,11 +1,11 @@
 [[data]]
-== Spring Data Integration
+= Spring Data Integration
 
 Spring Security provides Spring Data integration that allows referring to the current user within your queries.
 It is not only useful but necessary to include the user in the queries to support paged results since filtering the results afterwards would not scale.
 
 [[data-configuration]]
-=== Spring Data & Spring Security Configuration
+== Spring Data & Spring Security Configuration
 
 To use this support, add `org.springframework.security:spring-security-data` dependency and provide a bean of type `SecurityEvaluationContextExtension`.
 In Java Configuration, this would look like:
@@ -38,7 +38,7 @@ In XML Configuration, this would look like:
 ----
 
 [[data-query]]
-=== Security Expressions within @Query
+== Security Expressions within @Query
 
 Now Spring Security can be used within your queries.
 For example:

+ 1 - 1
docs/modules/ROOT/pages/servlet/integrations/jackson.adoc

@@ -1,5 +1,5 @@
 [[jackson]]
-== Jackson Support
+= Jackson Support
 
 Spring Security provides Jackson support for persisting Spring Security related classes.
 This can improve the performance of serializing Spring Security related classes when working with distributed sessions (i.e. session replication, Spring Session, etc).

+ 8 - 8
docs/modules/ROOT/pages/servlet/integrations/jsp-taglibs.adoc

@@ -1,9 +1,9 @@
 [[taglibs]]
-== JSP Tag Libraries
+= JSP Tag Libraries
 Spring Security has its own taglib which provides basic support for accessing security information and applying security constraints in JSPs.
 
 
-=== Declaring the Taglib
+== Declaring the Taglib
 To use any of the tags, you must have the security taglib declared in your JSP:
 
 [source,xml]
@@ -12,7 +12,7 @@ To use any of the tags, you must have the security taglib declared in your JSP:
 ----
 
 [[taglibs-authorize]]
-=== The authorize Tag
+== The authorize Tag
 This tag is used to determine whether its contents should be evaluated or not.
 In Spring Security 3.0, it can be used in two ways footnote:[
 The legacy options from Spring Security 2.0 are also supported, but discouraged.
@@ -65,7 +65,7 @@ This approach can also be combined with a `method` attribute, supplying the HTTP
 The Boolean result of evaluating the tag (whether it grants or denies access) can be stored in a page context scope variable by setting the `var` attribute to the variable name, avoiding the need for duplicating and re-evaluating the condition at other points in the page.
 
 
-==== Disabling Tag Authorization for Testing
+=== Disabling Tag Authorization for Testing
 Hiding a link in a page for unauthorized users doesn't prevent them from accessing the URL.
 They could just type it into their browser directly, for example.
 As part of your testing process, you may want to reveal the hidden areas in order to check that links really are secured at the back end.
@@ -77,7 +77,7 @@ Try running the "tutorial" sample application with this property enabled, for ex
 You can also set the properties `spring.security.securedUIPrefix` and `spring.security.securedUISuffix` if you want to change surrounding text from the default `span` tags (or use empty strings to remove it completely).
 
 
-=== The authentication Tag
+== The authentication Tag
 This tag allows access to the current `Authentication` object stored in the security context.
 It renders a property of the object directly in the JSP.
 So, for example, if the `principal` property of the `Authentication` is an instance of Spring Security's `UserDetails` object, then using `<sec:authentication property="principal.username" />` will render the name of the current user.
@@ -86,7 +86,7 @@ Of course, it isn't necessary to use JSP tags for this kind of thing and some pe
 You can access the `Authentication` object in your MVC controller (by calling `SecurityContextHolder.getContext().getAuthentication()`) and add the data directly to your model for rendering by the view.
 
 
-=== The accesscontrollist Tag
+== The accesscontrollist Tag
 This tag is only valid when used with Spring Security's ACL module.
 It checks a comma-separated list of required permissions for a specified domain object.
 If the current user has all of those permissions, then the tag body will be evaluated.
@@ -113,7 +113,7 @@ The `Acl` will be invoked with the required permissions to check if all of them
 This tag also supports the `var` attribute, in the same way as the `authorize` tag.
 
 [[taglibs-csrfinput]]
-=== The csrfInput Tag
+== The csrfInput Tag
 If CSRF protection is enabled, this tag inserts a hidden form field with the correct name and value for the CSRF protection token.
 If CSRF protection is not enabled, this tag outputs nothing.
 
@@ -134,7 +134,7 @@ Spring Security handles Spring forms automatically.
 ----
 
 [[taglibs-csrfmeta]]
-=== The csrfMetaTags Tag
+== The csrfMetaTags Tag
 If CSRF protection is enabled, this tag inserts meta tags containing the CSRF protection token form field and header names and CSRF protection token value.
 These meta tags are useful for employing CSRF protection within JavaScript in your applications.
 

+ 1 - 1
docs/modules/ROOT/pages/servlet/integrations/localization.adoc

@@ -1,5 +1,5 @@
 [[localization]]
-== Localization
+= Localization
 Spring Security supports localization of exception messages that end users are likely to see.
 If your application is designed for English-speaking users, you don't need to do anything as by default all Security messages are in English.
 If you need to support other locales, everything you need to know is contained in this section.

+ 8 - 8
docs/modules/ROOT/pages/servlet/integrations/mvc.adoc

@@ -1,11 +1,11 @@
 [[mvc]]
-== Spring MVC Integration
+= Spring MVC Integration
 
 Spring Security provides a number of optional integrations with Spring MVC.
 This section covers the integration in further detail.
 
 [[mvc-enablewebmvcsecurity]]
-=== @EnableWebMvcSecurity
+== @EnableWebMvcSecurity
 
 NOTE: As of Spring Security 4.0, `@EnableWebMvcSecurity` is deprecated.
 The replacement is `@EnableWebSecurity` which will determine adding the Spring MVC features based upon the classpath.
@@ -16,7 +16,7 @@ NOTE: Spring Security provides the configuration using Spring MVC's https://docs
 This means that if you are using more advanced options, like integrating with `WebMvcConfigurationSupport` directly, then you will need to manually provide the Spring Security configuration.
 
 [[mvc-requestmatcher]]
-=== MvcRequestMatcher
+== MvcRequestMatcher
 
 Spring Security provides deep integration with how Spring MVC matches on URLs with `MvcRequestMatcher`.
 This is helpful to ensure your Security rules match the logic used to handle your requests.
@@ -212,7 +212,7 @@ or in XML
 ----
 
 [[mvc-authentication-principal]]
-=== @AuthenticationPrincipal
+== @AuthenticationPrincipal
 
 Spring Security provides `AuthenticationPrincipalArgumentResolver` which can automatically resolve the current `Authentication.getPrincipal()` for Spring MVC arguments.
 By using `@EnableWebSecurity` you will automatically have this added to your Spring MVC configuration.
@@ -448,7 +448,7 @@ open fun findMessagesForUser(@CurrentUser customUser: CustomUser?): ModelAndView
 
 
 [[mvc-async]]
-=== Spring MVC Async Integration
+== Spring MVC Async Integration
 
 Spring Web MVC 3.2+ has excellent support for https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-async[Asynchronous Request Processing].
 With no additional configuration, Spring Security will automatically setup the `SecurityContext` to the `Thread` that invokes a `Callable` returned by your controllers.
@@ -495,9 +495,9 @@ This is because `DeferredResult` is processed by the users and thus there is no
 However, you can still use <<concurrency,Concurrency Support>> to provide transparent integration with Spring Security.
 
 [[mvc-csrf]]
-=== Spring MVC and CSRF Integration
+== Spring MVC and CSRF Integration
 
-==== Automatic Token Inclusion
+=== Automatic Token Inclusion
 
 Spring Security will automatically <<servlet-csrf-include,include the CSRF Token>> within forms that use the https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/view.html#view-jsp-formtaglib-formtag[Spring MVC form tag].
 For example, the following JSP:
@@ -541,7 +541,7 @@ Will output HTML that is similar to the following:
 ----
 
 [[mvc-csrf-resolver]]
-==== Resolving the CsrfToken
+=== Resolving the CsrfToken
 
 Spring Security provides `CsrfTokenArgumentResolver` which can automatically resolve the current `CsrfToken` for Spring MVC arguments.
 By using <<jc-hello-wsca,@EnableWebSecurity>> you will automatically have this added to your Spring MVC configuration.

+ 13 - 13
docs/modules/ROOT/pages/servlet/integrations/servlet-api.adoc

@@ -1,14 +1,14 @@
 [[servletapi]]
-== Servlet API integration
+= Servlet API integration
 This section describes how Spring Security is integrated with the Servlet API.
 
 
 [[servletapi-25]]
-=== Servlet 2.5+ Integration
+== Servlet 2.5+ Integration
 
 
 [[servletapi-remote-user]]
-==== HttpServletRequest.getRemoteUser()
+=== HttpServletRequest.getRemoteUser()
 The https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[HttpServletRequest.getRemoteUser()] will return the result of `SecurityContextHolder.getContext().getAuthentication().getName()` which is typically the current username.
 This can be useful if you want to display the current username in your application.
 Additionally, checking if this is null can be used to indicate if a user has authenticated or is anonymous.
@@ -16,7 +16,7 @@ Knowing if the user is authenticated or not can be useful for determining if cer
 
 
 [[servletapi-user-principal]]
-==== HttpServletRequest.getUserPrincipal()
+=== HttpServletRequest.getUserPrincipal()
 The https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[HttpServletRequest.getUserPrincipal()] will return the result of `SecurityContextHolder.getContext().getAuthentication()`.
 This means it is an `Authentication` which is typically an instance of `UsernamePasswordAuthenticationToken` when using username and password based authentication.
 This can be useful if you need additional information about your user.
@@ -55,7 +55,7 @@ Instead, one should centralize it to reduce any coupling of Spring Security and
 ====
 
 [[servletapi-user-in-role]]
-==== HttpServletRequest.isUserInRole(String)
+=== HttpServletRequest.isUserInRole(String)
 The https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[HttpServletRequest.isUserInRole(String)] will determine if `SecurityContextHolder.getContext().getAuthentication().getAuthorities()` contains a `GrantedAuthority` with the role passed into `isUserInRole(String)`.
 Typically users should not pass in the "ROLE_" prefix into this method since it is added automatically.
 For example, if you want to determine if the current user has the authority "ROLE_ADMIN", you could use the following:
@@ -78,18 +78,18 @@ This might be useful to determine if certain UI components should be displayed.
 For example, you might display admin links only if the current user is an admin.
 
 [[servletapi-3]]
-=== Servlet 3+ Integration
+== Servlet 3+ Integration
 The following section describes the Servlet 3 methods that Spring Security integrates with.
 
 
 [[servletapi-authenticate]]
-==== HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)
+=== HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)
 The https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#authenticate%28javax.servlet.http.HttpServletResponse%29[HttpServletRequest.authenticate(HttpServletRequest,HttpServletResponse)] method can be used to ensure that a user is authenticated.
 If they are not authenticated, the configured AuthenticationEntryPoint will be used to request the user to authenticate (i.e. redirect to the login page).
 
 
 [[servletapi-login]]
-==== HttpServletRequest.login(String,String)
+=== HttpServletRequest.login(String,String)
 The https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login%28java.lang.String,%20java.lang.String%29[HttpServletRequest.login(String,String)] method can be used to authenticate the user with the current `AuthenticationManager`.
 For example, the following would attempt to authenticate with the username "user" and password "password":
 
@@ -121,7 +121,7 @@ It is not necessary to catch the ServletException if you want Spring Security to
 ====
 
 [[servletapi-logout]]
-==== HttpServletRequest.logout()
+=== HttpServletRequest.logout()
 The https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout%28%29[HttpServletRequest.logout()] method can be used to log the current user out.
 
 Typically this means that the SecurityContextHolder will be cleared out, the HttpSession will be invalidated, any "Remember Me" authentication will be cleaned up, etc.
@@ -130,7 +130,7 @@ It is important to note that after HttpServletRequest.logout() has been invoked,
 Typically this would involve a redirect to the welcome page.
 
 [[servletapi-start-runnable]]
-==== AsyncContext.start(Runnable)
+=== AsyncContext.start(Runnable)
 The https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html#start%28java.lang.Runnable%29[AsyncContext.start(Runnable)] method that ensures your credentials will be propagated to the new Thread.
 Using Spring Security's concurrency support, Spring Security overrides the AsyncContext.start(Runnable) to ensure that the current SecurityContext is used when processing the Runnable.
 For example, the following would output the current user's Authentication:
@@ -174,7 +174,7 @@ async.start {
 ====
 
 [[servletapi-async]]
-==== Async Servlet Support
+=== Async Servlet Support
 If you are using Java Based configuration, you are ready to go.
 If you are using XML configuration, there are a few updates that are necessary.
 The first step is to ensure you have updated your web.xml to use at least the 3.0 schema as shown below:
@@ -265,9 +265,9 @@ When Spring Security automatically saved the SecurityContext on committing the H
 Since version 3.2, Spring Security is smart enough to no longer automatically save the SecurityContext on committing the HttpServletResponse as soon as HttpServletRequest.startAsync() is invoked.
 
 [[servletapi-31]]
-=== Servlet 3.1+ Integration
+== Servlet 3.1+ Integration
 The following section describes the Servlet 3.1 methods that Spring Security integrates with.
 
 [[servletapi-change-session-id]]
-==== HttpServletRequest#changeSessionId()
+=== HttpServletRequest#changeSessionId()
 The https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#changeSessionId()[HttpServletRequest.changeSessionId()] is the default method for protecting against <<ns-session-fixation,Session Fixation>> attacks in Servlet 3.1 and higher.

+ 16 - 16
docs/modules/ROOT/pages/servlet/integrations/websocket.adoc

@@ -1,5 +1,5 @@
 [[websocket]]
-== WebSocket Security
+= WebSocket Security
 
 Spring Security 4 added support for securing https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html[Spring's WebSocket support].
 This section describes how to use Spring Security's WebSocket support.
@@ -12,7 +12,7 @@ Additionally, JSR-356 does not provide a way to intercept messages, so security
 ****
 
 [[websocket-configuration]]
-=== WebSocket Configuration
+== WebSocket Configuration
 
 Spring Security 4.0 has introduced authorization support for WebSockets through the Spring Messaging abstraction.
 To configure authorization using Java Configuration, simply extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`.
@@ -69,7 +69,7 @@ This will ensure that:
 <3> Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in <<websocket-authorization>>
 
 [[websocket-authentication]]
-=== WebSocket Authentication
+== WebSocket Authentication
 
 WebSockets reuse the same authentication information that is found in the HTTP request when the WebSocket connection was made.
 This means that the `Principal` on the `HttpServletRequest` will be handed off to WebSockets.
@@ -78,7 +78,7 @@ If you are using Spring Security, the `Principal` on the `HttpServletRequest` is
 More concretely, to ensure a user has authenticated to your WebSocket application, all that is necessary is to ensure that you setup Spring Security to authenticate your HTTP based web application.
 
 [[websocket-authorization]]
-=== WebSocket Authorization
+== WebSocket Authorization
 
 Spring Security 4.0 has introduced authorization support for WebSockets through the Spring Messaging abstraction.
 To configure authorization using Java Configuration, simply extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`.
@@ -168,12 +168,12 @@ This will ensure that:
 <6> Any other message with a destination is rejected. This is a good idea to ensure that you do not miss any messages.
 
 [[websocket-authorization-notes]]
-==== WebSocket Authorization Notes
+=== WebSocket Authorization Notes
 
 In order to properly secure your application it is important to understand Spring's WebSocket support.
 
 [[websocket-authorization-notes-messagetypes]]
-===== WebSocket Authorization on Message Types
+==== WebSocket Authorization on Message Types
 
 It is important to understand the distinction between SUBSCRIBE and MESSAGE types of messages and how it works within Spring.
 
@@ -188,7 +188,7 @@ If we allowed sending a MESSAGE to "/topic/system/notifications", then clients c
 In general, it is common for applications to deny any MESSAGE sent to a destination that starts with the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp[broker prefix] (i.e. "/topic/" or "/queue/").
 
 [[websocket-authorization-notes-destinations]]
-===== WebSocket Authorization on Destinations
+==== WebSocket Authorization on Destinations
 
 It is also is important to understand how destinations are transformed.
 
@@ -206,7 +206,7 @@ In general, it is common for applications to deny any SUBSCRIBE sent to a messag
 Of course we may provide exceptions to account for things like
 
 [[websocket-authorization-notes-outbound]]
-==== Outbound Messages
+=== Outbound Messages
 
 Spring contains a section titled https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-message-flow[Flow of Messages] that describes how messages flow through the system.
 It is important to note that Spring Security only secures the `clientInboundChannel`.
@@ -217,13 +217,13 @@ For every message that goes in, there are typically many more that go out.
 Instead of securing the outbound messages, we encourage securing the subscription to the endpoints.
 
 [[websocket-sameorigin]]
-=== Enforcing Same Origin Policy
+== Enforcing Same Origin Policy
 
 It is important to emphasize that the browser does not enforce the https://en.wikipedia.org/wiki/Same-origin_policy[Same Origin Policy] for WebSocket connections.
 This is an extremely important consideration.
 
 [[websocket-sameorigin-why]]
-==== Why Same Origin?
+=== Why Same Origin?
 
 Consider the following scenario.
 A user visits bank.com and authenticates to their account.
@@ -238,13 +238,13 @@ Since SockJS tries to emulate WebSockets it also bypasses the Same Origin Policy
 This means developers need to explicitly protect their applications from external domains when using SockJS.
 
 [[websocket-sameorigin-spring]]
-==== Spring WebSocket Allowed Origin
+=== Spring WebSocket Allowed Origin
 
 Fortunately, since Spring 4.1.5 Spring's WebSocket and SockJS support restricts access to the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-allowed-origins[current domain].
 Spring Security adds an additional layer of protection to provide https://en.wikipedia.org/wiki/Defense_in_depth_(computing)[defence in depth].
 
 [[websocket-sameorigin-csrf]]
-==== Adding CSRF to Stomp Headers
+=== Adding CSRF to Stomp Headers
 
 By default Spring Security requires the <<csrf,CSRF token>> in any CONNECT message type.
 This ensures that only a site that has access to the CSRF token can connect.
@@ -310,7 +310,7 @@ stompClient.connect(headers, function(frame) {
 ----
 
 [[websocket-sameorigin-disable]]
-==== Disable CSRF within WebSockets
+=== Disable CSRF within WebSockets
 
 If you want to allow other domains to access your site, you can disable Spring Security's protection.
 For example, in Java Configuration you can use the following:
@@ -348,13 +348,13 @@ open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfi
 
 
 [[websocket-sockjs]]
-=== Working with SockJS
+== Working with SockJS
 
 https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-fallback[SockJS] provides fallback transports to support older browsers.
 When using the fallback options we need to relax a few security constraints to allow SockJS to work with Spring Security.
 
 [[websocket-sockjs-sameorigin]]
-==== SockJS & frame-options
+=== SockJS & frame-options
 
 SockJS may use an https://github.com/sockjs/sockjs-client/tree/v0.3.4[transport that leverages an iframe].
 By default Spring Security will <<headers-frame-options,deny>> the site from being framed to prevent Clickjacking attacks.
@@ -418,7 +418,7 @@ open class WebSecurityConfig : WebSecurityConfigurerAdapter() {
 ====
 
 [[websocket-sockjs-csrf]]
-==== SockJS & Relaxing CSRF
+=== SockJS & Relaxing CSRF
 
 SockJS uses a POST on the CONNECT messages for any HTTP based transport.
 Typically we need to include the CSRF token in an HTTP header or an HTTP parameter.

+ 1615 - 1
docs/modules/ROOT/pages/servlet/saml2/index.adoc

@@ -1,4 +1,1618 @@
 [[servlet-saml2]]
 = SAML2
 
-include::saml2-login.adoc[]
+Spring Security provides comprehensive SAML 2 support.
+This section discusses how to integrate SAML 2 into your servlet based application.
+
+[[servlet-saml2login]]
+== SAML 2.0 Login
+:figures: images/servlet/saml2
+:icondir: images/icons
+
+The SAML 2.0 Login feature provides an application with the capability to act as a SAML 2.0 Relying Party, having users https://wiki.shibboleth.net/confluence/display/CONCEPT/FlowsAndConfig[log in] to the application by using their existing account at a SAML 2.0 Asserting Party (Okta, ADFS, etc).
+
+NOTE: SAML 2.0 Login is implemented by using the *Web Browser SSO Profile*, as specified in
+https://www.oasis-open.org/committees/download.php/35389/sstc-saml-profiles-errata-2.0-wd-06-diff.pdf#page=15[SAML 2 Profiles].
+
+[[servlet-saml2login-spring-security-history]]
+Since 2009, support for relying parties has existed as an https://github.com/spring-projects/spring-security-saml/tree/1e013b07a7772defd6a26fcfae187c9bf661ee8f#spring-saml[extension project].
+In 2019, the process began to port that into https://github.com/spring-projects/spring-security[Spring Security] proper.
+This process is similar to the one started in 2017 for <<oauth2,Spring Security's OAuth 2.0 support>>.
+
+[NOTE]
+====
+A working sample for {gh-samples-url}/servlet/spring-boot/java/saml2-login[SAML 2.0 Login] is available in the {gh-samples-url}[Spring Security Samples repository].
+====
+
+Let's take a look at how SAML 2.0 Relying Party Authentication works within Spring Security.
+First, we see that, like <<oauth2login, OAuth 2.0 Login>>, Spring Security takes the user to a third-party for performing authentication.
+It does this through a series of redirects.
+
+.Redirecting to Asserting Party Authentication
+image::{figures}/saml2webssoauthenticationrequestfilter.png[]
+
+The figure above builds off our <<servlet-securityfilterchain,`SecurityFilterChain`>> and <<servlet-authentication-abstractprocessingfilter, `AbstractAuthenticationProcessingFilter`>> diagrams:
+
+image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource `/private` for which it is not authorized.
+
+image:{icondir}/number_2.png[] Spring Security's <<servlet-authorization-filtersecurityinterceptor,`FilterSecurityInterceptor`>> indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
+
+image:{icondir}/number_3.png[] Since the user lacks authorization, the <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>> initiates __Start Authentication__.
+The configured <<servlet-authentication-authenticationentrypoint,`AuthenticationEntryPoint`>> is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`] which redirects to <<servlet-saml2login-sp-initiated-factory,the `<saml2:AuthnRequest>` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`.
+Or, if you've <<servlet-saml2login-relyingpartyregistrationrepository,configured more than one asserting party>>, it will first redirect to a picker page.
+
+image:{icondir}/number_4.png[] Next, the `Saml2WebSsoAuthenticationRequestFilter` creates, signs, serializes, and encodes a `<saml2:AuthnRequest>` using its configured <<servlet-saml2login-sp-initiated-factory,`Saml2AuthenticationRequestFactory`>>.
+
+image:{icondir}/number_5.png[] Then, the browser takes this `<saml2:AuthnRequest>` and presents it to the asserting party.
+The asserting party attempts to authentication the user.
+If successful, it will return a `<saml2:Response>` back to the browser.
+
+image:{icondir}/number_6.png[] The browser then POSTs the `<saml2:Response>` to the assertion consumer service endpoint.
+
+[[servlet-saml2login-authentication-saml2webssoauthenticationfilter]]
+.Authenticating a `<saml2:Response>`
+image::{figures}/saml2webssoauthenticationfilter.png[]
+
+The figure builds off our <<servlet-securityfilterchain,`SecurityFilterChain`>> diagram.
+
+image:{icondir}/number_1.png[] When the browser submits a `<saml2:Response>` to the application, it <<servlet-saml2login-authenticate-responses, delegates to `Saml2WebSsoAuthenticationFilter`>>.
+This filter calls its configured `AuthenticationConverter` to create a `Saml2AuthenticationToken` by extracting the response from the `HttpServletRequest`.
+This converter additionally resolves the <<servlet-saml2login-relyingpartyregistration, `RelyingPartyRegistration`>> and supplies it to `Saml2AuthenticationToken`.
+
+image:{icondir}/number_2.png[] Next, the filter passes the token to its configured <<servlet-authentication-providermanager,`AuthenticationManager`>>.
+By default, it will use the <<servlet-saml2login-architecture,`OpenSAML authentication provider`>>.
+
+image:{icondir}/number_3.png[] If authentication fails, then __Failure__
+
+* The <<servlet-authentication-securitycontextholder, `SecurityContextHolder`>> is cleared out.
+* The <<servlet-authentication-authenticationentrypoint,`AuthenticationEntryPoint`>> is invoked to restart the authentication process.
+
+image:{icondir}/number_4.png[] If authentication is successful, then __Success__.
+
+* The <<servlet-authentication-authentication, `Authentication`>> is set on the <<servlet-authentication-securitycontextholder, `SecurityContextHolder`>>.
+* The `Saml2WebSsoAuthenticationFilter` invokes `FilterChain#doFilter(request,response)` to continue with the rest of the application logic.
+
+[[servlet-saml2login-minimaldependencies]]
+=== Minimal Dependencies
+
+SAML 2.0 service provider support resides in `spring-security-saml2-service-provider`.
+It builds off of the OpenSAML library.
+
+[[servlet-saml2login-minimalconfiguration]]
+=== Minimal Configuration
+
+When using https://spring.io/projects/spring-boot[Spring Boot], configuring an application as a service provider consists of two basic steps.
+First, include the needed dependencies and second, indicate the necessary asserting party metadata.
+
+[NOTE]
+Also, this presupposes that you've already <<servlet-saml2login-metadata, registered the relying party with your asserting party>>.
+
+==== Specifying Identity Provider Metadata
+
+In a Spring Boot application, to specify an identity provider's metadata, simply do:
+
+[source,yml]
+----
+spring:
+  security:
+    saml2:
+      relyingparty:
+        registration:
+          adfs:
+            identityprovider:
+              entity-id: https://idp.example.com/issuer
+              verification.credentials:
+                - certificate-location: "classpath:idp.crt"
+              singlesignon.url: https://idp.example.com/issuer/sso
+              singlesignon.sign-request: false
+----
+
+where
+
+* `https://idp.example.com/issuer` is the value contained in the `Issuer` attribute of the SAML responses that the identity provider will issue
+* `classpath:idp.crt` is the location on the classpath for the identity provider's certificate for verifying SAML responses, and
+* `https://idp.example.com/issuer/sso` is the endpoint where the identity provider is expecting `AuthnRequest` s.
+
+And that's it!
+
+[NOTE]
+Identity Provider and Asserting Party are synonymous, as are Service Provider and Relying Party.
+These are frequently abbreviated as AP and RP, respectively.
+
+==== Runtime Expectations
+
+As configured above, the application processes any `+POST /login/saml2/sso/{registrationId}+` request containing a `SAMLResponse` parameter:
+
+[source,html]
+----
+POST /login/saml2/sso/adfs HTTP/1.1
+
+SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZ...
+----
+
+There are two ways to see induce your asserting party to generate a `SAMLResponse`:
+
+* First, you can navigate to your asserting party.
+It likely has some kind of link or button for each registered relying party that you can click to send the `SAMLResponse`.
+* Second, you can navigate to a protected page in your app, for example, `http://localhost:8080`.
+Your app then redirects to the configured asserting party which then sends the `SAMLResponse`.
+
+From here, consider jumping to:
+
+* <<servlet-saml2login-architecture,How SAML 2.0 Login Integrates with OpenSAML>>
+* <<servlet-saml2login-authenticatedprincipal,How to Use the `Saml2AuthenticatedPrincipal`>>
+* <<servlet-saml2login-sansboot,How to Override or Replace Spring Boot's Auto Configuration>>
+
+[[servlet-saml2login-architecture]]
+=== How SAML 2.0 Login Integrates with OpenSAML
+
+Spring Security's SAML 2.0 support has a couple of design goals:
+
+* First, rely on a library for SAML 2.0 operations and domain objects.
+To achieve this, Spring Security uses OpenSAML.
+* Second, ensure this library is not required when using Spring Security's SAML support.
+To achieve this, any interfaces or classes where Spring Security uses OpenSAML in the contract remain encapsulated.
+This makes it possible for you to switch out OpenSAML for some other library or even an unsupported version of OpenSAML.
+
+As a natural outcome of the above two goals, Spring Security's SAML API is quite small relative to other modules.
+Instead, classes like `OpenSaml4AuthenticationRequestFactory` and `OpenSaml4AuthenticationProvider` expose `Converter` s that customize various steps in the authentication process.
+
+For example, once your application receives a `SAMLResponse` and delegates to `Saml2WebSsoAuthenticationFilter`, the filter will delegate to `OpenSaml4AuthenticationProvider`.
+
+[NOTE]
+For backward compatibility, Spring Security will use the latest OpenSAML 3 by default.
+Note, though that OpenSAML 3 has reached it's end-of-life and updating to OpenSAML 4.x is recommended.
+For that reason, Spring Security supports both OpenSAML 3.x and 4.x.
+If you manage your OpenSAML dependency to 4.x, then Spring Security will select its OpenSAML 4.x implementations.
+
+.Authenticating an OpenSAML `Response`
+image:{figures}/opensamlauthenticationprovider.png[]
+
+This figure builds off of the <<servlet-saml2login-authentication-saml2webssoauthenticationfilter,`Saml2WebSsoAuthenticationFilter` diagram>>.
+
+image:{icondir}/number_1.png[] The `Saml2WebSsoAuthenticationFilter` formulates the `Saml2AuthenticationToken` and invokes the <<servlet-authentication-providermanager,`AuthenticationManager`>>.
+
+image:{icondir}/number_2.png[] The <<servlet-authentication-providermanager,`AuthenticationManager`>> invokes the OpenSAML authentication provider.
+
+image:{icondir}/number_3.png[] The authentication provider deserializes the response into an OpenSAML `Response` and checks its signature.
+If the signature is invalid, authentication fails.
+
+image:{icondir}/number_4.png[] Then, the provider <<servlet-saml2login-opensamlauthenticationprovider-decryption,decrypts any `EncryptedAssertion` elements>>.
+If any decryptions fail, authentication fails.
+
+image:{icondir}/number_5.png[] Next, the provider validates the response's `Issuer` and `Destination` values.
+If they don't match what's in the `RelyingPartyRegistration`, authentication fails.
+
+image:{icondir}/number_6.png[] After that, the provider verifies the signature of each `Assertion`.
+If any signature is invalid, authentication fails.
+Also, if neither the response nor the assertions have signatures, authentication fails.
+Either the response or all the assertions must have signatures.
+
+image:{icondir}/number_7.png[] Then, the provider <<servlet-saml2login-opensamlauthenticationprovider-decryption,decrypts any `EncryptedID` or `EncryptedAttribute` elements>>.
+If any decryptions fail, authentication fails.
+
+image:{icondir}/number_8.png[] Next, the provider validates each assertion's `ExpiresAt` and `NotBefore` timestamps, the `<Subject>` and any `<AudienceRestriction>` conditions.
+If any validations fail, authentication fails.
+
+image:{icondir}/number_9.png[] Following that, the provider takes the first assertion's `AttributeStatement` and maps it to a `Map<String, List<Object>>`.
+It also grants the `ROLE_USER` granted authority.
+
+image:{icondir}/number_10.png[] And finally, it takes the `NameID` from the first assertion, the `Map` of attributes, and the `GrantedAuthority` and constructs a `Saml2AuthenticatedPrincipal`.
+Then, it places that principal and the authorities into a `Saml2Authentication`.
+
+The resulting `Authentication#getPrincipal` is a Spring Security `Saml2AuthenticatedPrincipal` object, and `Authentication#getName` maps to the first assertion's `NameID` element.
+
+[[servlet-saml2login-opensaml-customization]]
+==== Customizing OpenSAML Configuration
+
+Any class that uses both Spring Security and OpenSAML should statically initialize `OpenSamlInitializationService` at the beginning of the class, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+static {
+	OpenSamlInitializationService.initialize();
+}
+----
+
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+companion object {
+    init {
+        OpenSamlInitializationService.initialize()
+    }
+}
+----
+====
+
+This replaces OpenSAML's `InitializationService#initialize`.
+
+Occasionally, it can be valuable to customize how OpenSAML builds, marshalls, and unmarshalls SAML objects.
+In these circumstances, you may instead want to call `OpenSamlInitializationService#requireInitialize(Consumer)` that gives you access to OpenSAML's `XMLObjectProviderFactory`.
+
+For example, when sending an unsigned AuthNRequest, you may want to force reauthentication.
+In that case, you can register your own `AuthnRequestMarshaller`, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+static {
+    OpenSamlInitializationService.requireInitialize(factory -> {
+        AuthnRequestMarshaller marshaller = new AuthnRequestMarshaller() {
+            @Override
+            public Element marshall(XMLObject object, Element element) throws MarshallingException {
+                configureAuthnRequest((AuthnRequest) object);
+                return super.marshall(object, element);
+            }
+
+            public Element marshall(XMLObject object, Document document) throws MarshallingException {
+                configureAuthnRequest((AuthnRequest) object);
+                return super.marshall(object, document);
+            }
+
+            private void configureAuthnRequest(AuthnRequest authnRequest) {
+                authnRequest.setForceAuthn(true);
+            }
+        }
+
+        factory.getMarshallerFactory().registerMarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME, marshaller);
+    });
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+companion object {
+    init {
+        OpenSamlInitializationService.requireInitialize {
+            val marshaller = object : AuthnRequestMarshaller() {
+                override fun marshall(xmlObject: XMLObject, element: Element): Element {
+                    configureAuthnRequest(xmlObject as AuthnRequest)
+                    return super.marshall(xmlObject, element)
+                }
+
+                override fun marshall(xmlObject: XMLObject, document: Document): Element {
+                    configureAuthnRequest(xmlObject as AuthnRequest)
+                    return super.marshall(xmlObject, document)
+                }
+
+                private fun configureAuthnRequest(authnRequest: AuthnRequest) {
+                    authnRequest.isForceAuthn = true
+                }
+            }
+            it.marshallerFactory.registerMarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME, marshaller)
+        }
+    }
+}
+----
+====
+
+The `requireInitialize` method may only be called once per application instance.
+
+[[servlet-saml2login-sansboot]]
+=== Overriding or Replacing Boot Auto Configuration
+
+There are two `@Bean` s that Spring Boot generates for a relying party.
+
+The first is a `WebSecurityConfigurerAdapter` that configures the app as a relying party.
+When including `spring-security-saml2-service-provider`, the `WebSecurityConfigurerAdapter` looks like:
+
+.Default JWT Configuration
+====
+.Java
+[source,java,role="primary"]
+----
+protected void configure(HttpSecurity http) {
+    http
+        .authorizeRequests(authorize -> authorize
+            .anyRequest().authenticated()
+        )
+        .saml2Login(withDefaults());
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+fun configure(http: HttpSecurity) {
+    http {
+        authorizeRequests {
+            authorize(anyRequest, authenticated)
+        }
+        saml2Login { }
+    }
+}
+----
+====
+
+If the application doesn't expose a `WebSecurityConfigurerAdapter` bean, then Spring Boot will expose the above default one.
+
+You can replace this by exposing the bean within the application:
+
+.Custom SAML 2.0 Login Configuration
+====
+.Java
+[source,java,role="primary"]
+----
+@EnableWebSecurity
+public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
+    protected void configure(HttpSecurity http) {
+        http
+            .authorizeRequests(authorize -> authorize
+                .mvcMatchers("/messages/**").hasAuthority("ROLE_USER")
+                .anyRequest().authenticated()
+            )
+            .saml2Login(withDefaults());
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@EnableWebSecurity
+class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() {
+    override fun configure(http: HttpSecurity) {
+        http {
+            authorizeRequests {
+                authorize("/messages/**", hasAuthority("ROLE_USER"))
+                authorize(anyRequest, authenticated)
+            }
+            saml2Login {
+            }
+        }
+    }
+}
+----
+====
+
+The above requires the role of `USER` for any URL that starts with `/messages/`.
+
+[[servlet-saml2login-relyingpartyregistrationrepository]]
+The second `@Bean` Spring Boot creates is a {security-api-url}org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistrationRepository.html[`RelyingPartyRegistrationRepository`], which represents the asserting party and relying party metadata.
+This includes things like the location of the SSO endpoint the relying party should use when requesting authentication from the asserting party.
+
+You can override the default by publishing your own `RelyingPartyRegistrationRepository` bean.
+For example, you can look up the asserting party's configuration by hitting its metadata endpoint like so:
+
+.Relying Party Registration Repository
+====
+.Java
+[source,java,role="primary"]
+----
+@Value("${metadata.location}")
+String assertingPartyMetadataLocation;
+
+@Bean
+public RelyingPartyRegistrationRepository relyingPartyRegistrations() {
+    RelyingPartyRegistration registration = RelyingPartyRegistrations
+            .fromMetadataLocation(assertingPartyMetadataLocation)
+            .registrationId("example")
+            .build();
+    return new InMemoryRelyingPartyRegistrationRepository(registration);
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Value("\${metadata.location}")
+var assertingPartyMetadataLocation: String? = null
+
+@Bean
+open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository? {
+    val registration = RelyingPartyRegistrations
+        .fromMetadataLocation(assertingPartyMetadataLocation)
+        .registrationId("example")
+        .build()
+    return InMemoryRelyingPartyRegistrationRepository(registration)
+}
+----
+====
+
+Or you can provide each detail manually, as you can see below:
+
+.Relying Party Registration Repository Manual Configuration
+====
+.Java
+[source,java,role="primary"]
+----
+@Value("${verification.key}")
+File verificationKey;
+
+@Bean
+public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
+    X509Certificate certificate = X509Support.decodeCertificate(this.verificationKey);
+    Saml2X509Credential credential = Saml2X509Credential.verification(certificate);
+    RelyingPartyRegistration registration = RelyingPartyRegistration
+            .withRegistrationId("example")
+            .assertingPartyDetails(party -> party
+                .entityId("https://idp.example.com/issuer")
+                .singleSignOnServiceLocation("https://idp.example.com/SSO.saml2")
+                .wantAuthnRequestsSigned(false)
+                .verificationX509Credentials(c -> c.add(credential))
+            )
+            .build();
+    return new InMemoryRelyingPartyRegistrationRepository(registration);
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Value("\${verification.key}")
+var verificationKey: File? = null
+
+@Bean
+open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository {
+    val certificate: X509Certificate? = X509Support.decodeCertificate(verificationKey!!)
+    val credential: Saml2X509Credential = Saml2X509Credential.verification(certificate)
+    val registration = RelyingPartyRegistration
+        .withRegistrationId("example")
+        .assertingPartyDetails { party: AssertingPartyDetails.Builder ->
+            party
+                .entityId("https://idp.example.com/issuer")
+                .singleSignOnServiceLocation("https://idp.example.com/SSO.saml2")
+                .wantAuthnRequestsSigned(false)
+                .verificationX509Credentials { c: MutableCollection<Saml2X509Credential?> ->
+                    c.add(
+                        credential
+                    )
+                }
+        }
+        .build()
+    return InMemoryRelyingPartyRegistrationRepository(registration)
+}
+----
+====
+
+[NOTE]
+Note that `X509Support` is an OpenSAML class, used here in the snippet for brevity
+
+[[servlet-saml2login-relyingpartyregistrationrepository-dsl]]
+
+Alternatively, you can directly wire up the repository using the DSL, which will also override the auto-configured `WebSecurityConfigurerAdapter`:
+
+.Custom Relying Party Registration DSL
+====
+.Java
+[source,java,role="primary"]
+----
+@EnableWebSecurity
+public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
+    protected void configure(HttpSecurity http) {
+        http
+            .authorizeRequests(authorize -> authorize
+                .mvcMatchers("/messages/**").hasAuthority("ROLE_USER")
+                .anyRequest().authenticated()
+            )
+            .saml2Login(saml2 -> saml2
+                .relyingPartyRegistrationRepository(relyingPartyRegistrations())
+            );
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@EnableWebSecurity
+class MyCustomSecurityConfiguration : WebSecurityConfigurerAdapter() {
+    override fun configure(http: HttpSecurity) {
+        http {
+            authorizeRequests {
+                authorize("/messages/**", hasAuthority("ROLE_USER"))
+                authorize(anyRequest, authenticated)
+            }
+            saml2Login {
+                relyingPartyRegistrationRepository = relyingPartyRegistrations()
+            }
+        }
+    }
+}
+----
+====
+
+[NOTE]
+A relying party can be multi-tenant by registering more than one relying party in the `RelyingPartyRegistrationRepository`.
+
+[[servlet-saml2login-relyingpartyregistration]]
+=== RelyingPartyRegistration
+A {security-api-url}org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.html[`RelyingPartyRegistration`]
+instance represents a link between an relying party and assering party's metadata.
+
+In a `RelyingPartyRegistration`, you can provide relying party metadata like its `Issuer` value, where it expects SAML Responses to be sent to, and any credentials that it owns for the purposes of signing or decrypting payloads.
+
+Also, you can provide asserting party metadata like its `Issuer` value, where it expects AuthnRequests to be sent to, and any public credentials that it owns for the purposes of the relying party verifying or encrypting payloads.
+
+The following `RelyingPartyRegistration` is the minimum required for most setups:
+
+====
+.Java
+[source,java,role="primary"]
+----
+RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
+        .fromMetadataLocation("https://ap.example.org/metadata")
+        .registrationId("my-id")
+        .build();
+----
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val relyingPartyRegistration = RelyingPartyRegistrations
+    .fromMetadataLocation("https://ap.example.org/metadata")
+    .registrationId("my-id")
+    .build()
+----
+====
+
+Note that you can also create a `RelyingPartyRegistration` from an arbitrary `InputStream` source.
+One such example is when the metadata is stored in a database:
+
+[source,java]
+----
+String xml = fromDatabase();
+try (InputStream source = new ByteArrayInputStream(xml.getBytes())) {
+    RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
+            .fromMetadata(source)
+            .registrationId("my-id")
+            .build();
+}
+----
+
+Though a more sophisticated setup is also possible, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("my-id")
+        .entityId("{baseUrl}/{registrationId}")
+        .decryptionX509Credentials(c -> c.add(relyingPartyDecryptingCredential()))
+        .assertionConsumerServiceLocation("/my-login-endpoint/{registrationId}")
+        .assertingPartyDetails(party -> party
+                .entityId("https://ap.example.org")
+                .verificationX509Credentials(c -> c.add(assertingPartyVerifyingCredential()))
+                .singleSignOnServiceLocation("https://ap.example.org/SSO.saml2")
+        )
+        .build();
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val relyingPartyRegistration =
+    RelyingPartyRegistration.withRegistrationId("my-id")
+        .entityId("{baseUrl}/{registrationId}")
+        .decryptionX509Credentials { c: MutableCollection<Saml2X509Credential?> ->
+            c.add(relyingPartyDecryptingCredential())
+        }
+        .assertionConsumerServiceLocation("/my-login-endpoint/{registrationId}")
+        .assertingPartyDetails { party -> party
+                .entityId("https://ap.example.org")
+                .verificationX509Credentials { c -> c.add(assertingPartyVerifyingCredential()) }
+                .singleSignOnServiceLocation("https://ap.example.org/SSO.saml2")
+        }
+        .build()
+----
+====
+
+[TIP]
+The top-level metadata methods are details about the relying party.
+The methods inside `assertingPartyDetails` are details about the asserting party.
+
+[NOTE]
+The location where a relying party is expecting SAML Responses is the Assertion Consumer Service Location.
+
+The default for the relying party's `entityId` is `+{baseUrl}/saml2/service-provider-metadata/{registrationId}+`.
+This is this value needed when configuring the asserting party to know about your relying party.
+
+The default for the `assertionConsumerServiceLocation` is `+/login/saml2/sso/{registrationId}+`.
+It's mapped by default to <<servlet-saml2login-authentication-saml2webssoauthenticationfilter,`Saml2WebSsoAuthenticationFilter`>> in the filter chain.
+
+[[servlet-saml2login-rpr-uripatterns]]
+==== URI Patterns
+
+You probably noticed in the above examples the `+{baseUrl}+` and `+{registrationId}+` placeholders.
+
+These are useful for generating URIs. As such, the relying party's `entityId` and `assertionConsumerServiceLocation` support the following placeholders:
+
+* `baseUrl` - the scheme, host, and port of a deployed application
+* `registrationId` - the registration id for this relying party
+* `baseScheme` - the scheme of a deployed application
+* `baseHost` - the host of a deployed application
+* `basePort` - the port of a deployed application
+
+For example, the `assertionConsumerServiceLocation` defined above was:
+
+`+/my-login-endpoint/{registrationId}+`
+
+which in a deployed application would translate to
+
+`+/my-login-endpoint/adfs+`
+
+The `entityId` above was defined as:
+
+`+{baseUrl}/{registrationId}+`
+
+which in a deployed application would translate to
+
+`+https://rp.example.com/adfs+`
+
+[[servlet-saml2login-rpr-credentials]]
+==== Credentials
+
+You also likely noticed the credential that was used.
+
+Oftentimes, a relying party will use the same key to sign payloads as well as decrypt them.
+Or it will use the same key to verify payloads as well as encrypt them.
+
+Because of this, Spring Security ships with `Saml2X509Credential`, a SAML-specific credential that simplifies configuring the same key for different use cases.
+
+At a minimum, it's necessary to have a certificate from the asserting party so that the asserting party's signed responses can be verified.
+
+To construct a `Saml2X509Credential` that you'll use to verify assertions from the asserting party, you can load the file and use
+the `CertificateFactory` like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+Resource resource = new ClassPathResource("ap.crt");
+try (InputStream is = resource.getInputStream()) {
+    X509Certificate certificate = (X509Certificate)
+            CertificateFactory.getInstance("X.509").generateCertificate(is);
+    return Saml2X509Credential.verification(certificate);
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val resource = ClassPathResource("ap.crt")
+resource.inputStream.use {
+    return Saml2X509Credential.verification(
+        CertificateFactory.getInstance("X.509").generateCertificate(it) as X509Certificate?
+    )
+}
+----
+====
+
+Let's say that the asserting party is going to also encrypt the assertion.
+In that case, the relying party will need a private key to be able to decrypt the encrypted value.
+
+In that case, you'll need an `RSAPrivateKey` as well as its corresponding `X509Certificate`.
+You can load the first using Spring Security's `RsaKeyConverters` utility class and the second as you did before:
+
+====
+.Java
+[source,java,role="primary"]
+----
+X509Certificate certificate = relyingPartyDecryptionCertificate();
+Resource resource = new ClassPathResource("rp.crt");
+try (InputStream is = resource.getInputStream()) {
+    RSAPrivateKey rsa = RsaKeyConverters.pkcs8().convert(is);
+    return Saml2X509Credential.decryption(rsa, certificate);
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val certificate: X509Certificate = relyingPartyDecryptionCertificate()
+val resource = ClassPathResource("rp.crt")
+resource.inputStream.use {
+    val rsa: RSAPrivateKey = RsaKeyConverters.pkcs8().convert(it)
+    return Saml2X509Credential.decryption(rsa, certificate)
+}
+----
+====
+
+[TIP]
+When you specify the locations of these files as the appropriate Spring Boot properties, then Spring Boot will perform these conversions for you.
+
+[[servlet-saml2login-rpr-relyingpartyregistrationresolver]]
+==== Resolving the Relying Party from the Request
+
+As seen so far, Spring Security resolves the `RelyingPartyRegistration` by looking for the registration id in the URI path.
+
+There are a number of reasons you may want to customize. Among them:
+
+* You may know that you will never be a multi-tenant application and so want to have a simpler URL scheme
+* You may identify tenants in a way other than by the URI path
+
+To customize the way that a `RelyingPartyRegistration` is resolved, you can configure a custom `Converter<HttpServletRequest, RelyingPartyRegistration>`.
+The default looks up the registration id from the URI's last path element and looks it up in your `RelyingPartyRegistrationRepository`.
+
+You can provide a simpler resolver that, for example, always returns the same relying party:
+
+====
+.Java
+[source,java,role="primary"]
+----
+public class SingleRelyingPartyRegistrationResolver
+        implements Converter<HttpServletRequest, RelyingPartyRegistration> {
+
+    @Override
+    public RelyingPartyRegistration convert(HttpServletRequest request) {
+        return this.relyingParty;
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+class SingleRelyingPartyRegistrationResolver : Converter<HttpServletRequest?, RelyingPartyRegistration?> {
+    override fun convert(request: HttpServletRequest?): RelyingPartyRegistration? {
+        return this.relyingParty
+    }
+}
+----
+====
+
+Then, you can provide this resolver to the appropriate filters that <<servlet-saml2login-sp-initiated-factory, produce `<saml2:AuthnRequest>` s>>, <<servlet-saml2login-authenticate-responses, authenticate `<saml2:Response>` s>>, and <<servlet-saml2login-metadata, produce `<saml2:SPSSODescriptor>` metadata>>.
+
+[NOTE]
+Remember that if you have any placeholders in your `RelyingPartyRegistration`, your resolver implementation should resolve them.
+
+[[servlet-saml2login-rpr-duplicated]]
+==== Duplicated Relying Party Configurations
+
+When an application uses multiple asserting parties, some configuration is duplicated between `RelyingPartyRegistration` instances:
+
+* The relying party's `entityId`
+* Its `assertionConsumerServiceLocation`, and
+* Its credentials, for example its signing or decryption credentials
+
+What's nice about this setup is credentials may be more easily rotated for some identity providers vs others.
+
+The duplication can be alleviated in a few different ways.
+
+First, in YAML this can be alleviated with references, like so:
+
+[source,yaml]
+----
+spring:
+  security:
+    saml2:
+      relyingparty:
+        okta:
+          signing.credentials: &relying-party-credentials
+            - private-key-location: classpath:rp.key
+            - certificate-location: classpath:rp.crt
+          identityprovider:
+            entity-id: ...
+        azure:
+          signing.credentials: *relying-party-credentials
+          identityprovider:
+            entity-id: ...
+----
+
+Second, in a database, it's not necessary to replicate `RelyingPartyRegistration` 's model.
+
+Third, in Java, you can create a custom configuration method, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+private RelyingPartyRegistration.Builder
+        addRelyingPartyDetails(RelyingPartyRegistration.Builder builder) {
+
+    Saml2X509Credential signingCredential = ...
+    builder.signingX509Credentials(c -> c.addAll(signingCredential));
+    // ... other relying party configurations
+}
+
+@Bean
+public RelyingPartyRegistrationRepository relyingPartyRegistrations() {
+    RelyingPartyRegistration okta = addRelyingPartyDetails(
+            RelyingPartyRegistrations
+                .fromMetadataLocation(oktaMetadataUrl)
+                .registrationId("okta")).build();
+
+    RelyingPartyRegistration azure = addRelyingPartyDetails(
+            RelyingPartyRegistrations
+                .fromMetadataLocation(oktaMetadataUrl)
+                .registrationId("azure")).build();
+
+    return new InMemoryRelyingPartyRegistrationRepository(okta, azure);
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+private fun addRelyingPartyDetails(builder: RelyingPartyRegistration.Builder): RelyingPartyRegistration.Builder {
+    val signingCredential: Saml2X509Credential = ...
+    builder.signingX509Credentials { c: MutableCollection<Saml2X509Credential?> ->
+        c.add(
+            signingCredential
+        )
+    }
+    // ... other relying party configurations
+}
+
+@Bean
+open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository? {
+    val okta = addRelyingPartyDetails(
+        RelyingPartyRegistrations
+            .fromMetadataLocation(oktaMetadataUrl)
+            .registrationId("okta")
+    ).build()
+    val azure = addRelyingPartyDetails(
+        RelyingPartyRegistrations
+            .fromMetadataLocation(oktaMetadataUrl)
+            .registrationId("azure")
+    ).build()
+    return InMemoryRelyingPartyRegistrationRepository(okta, azure)
+}
+----
+====
+
+[[servlet-saml2login-sp-initiated-factory]]
+=== Producing `<saml2:AuthnRequest>` s
+
+As stated earlier, Spring Security's SAML 2.0 support produces a `<saml2:AuthnRequest>` to commence authentication with the asserting party.
+
+Spring Security achieves this in part by registering the `Saml2WebSsoAuthenticationRequestFilter` in the filter chain.
+This filter by default responds to endpoint `+/saml2/authenticate/{registrationId}+`.
+
+For example, if you were deployed to `https://rp.example.com` and you gave your registration an ID of `okta`, you could navigate to:
+
+`https://rp.example.org/saml2/authenticate/ping`
+
+and the result would be a redirect that included a `SAMLRequest` parameter containing the signed, deflated, and encoded `<saml2:AuthnRequest>`.
+
+[[servlet-saml2login-sp-initiated-factory-signing]]
+==== Changing How the `<saml2:AuthnRequest>` Gets Sent
+
+By default, Spring Security signs each `<saml2:AuthnRequest>` and send it as a GET to the asserting party.
+
+Many asserting parties don't require a signed `<saml2:AuthnRequest>`.
+This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so:
+
+
+.Not Requiring Signed AuthnRequests
+====
+.Boot
+[source,yaml,role="primary"]
+----
+spring:
+  security:
+    saml2:
+      relyingparty:
+        okta:
+          identityprovider:
+            entity-id: ...
+            singlesignon.sign-request: false
+----
+
+.Java
+[source,java,role="secondary"]
+----
+RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
+        // ...
+        .assertingPartyDetails(party -> party
+            // ...
+            .wantAuthnRequestsSigned(false)
+        )
+        .build();
+----
+
+.Kotlin
+[source,java,role="secondary"]
+----
+var relyingPartyRegistration: RelyingPartyRegistration =
+    RelyingPartyRegistration.withRegistrationId("okta")
+        // ...
+        .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
+                // ...
+                .wantAuthnRequestsSigned(false)
+        }
+        .build();
+----
+====
+
+Otherwise, you will need to specify a private key to `RelyingPartyRegistration#signingX509Credentials` so that Spring Security can sign the `<saml2:AuthnRequest>` before sending.
+
+[[servlet-saml2login-sp-initiated-factory-algorithm]]
+By default, Spring Security will sign the `<saml2:AuthnRequest>` using `rsa-sha256`, though some asserting parties will require a different algorithm, as indicated in their metadata.
+
+You can configure the algorithm based on the asserting party's <<servlet-saml2login-relyingpartyregistrationrepository,metadata using `RelyingPartyRegistrations`>>.
+
+Or, you can provide it manually:
+
+====
+.Java
+[source,java,role="primary"]
+----
+String metadataLocation = "classpath:asserting-party-metadata.xml";
+RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
+        // ...
+        .assertingPartyDetails((party) -> party
+            // ...
+            .signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512))
+        )
+        .build();
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+var metadataLocation = "classpath:asserting-party-metadata.xml"
+var relyingPartyRegistration: RelyingPartyRegistration =
+    RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
+        // ...
+        .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
+                // ...
+                .signingAlgorithms { sign: MutableList<String?> ->
+                    sign.add(
+                        SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512
+                    )
+                }
+        }
+        .build();
+----
+====
+
+NOTE: The snippet above uses the OpenSAML `SignatureConstants` class to supply the algorithm name.
+But, that's just for convenience.
+Since the datatype is `String`, you can supply the name of the algorithm directly.
+
+[[servlet-saml2login-sp-initiated-factory-binding]]
+Some asserting parties require that the `<saml2:AuthnRequest>` be POSTed.
+This can be configured automatically via `RelyingPartyRegistrations`, or you can supply it manually, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
+        // ...
+        .assertingPartyDetails(party -> party
+            // ...
+            .singleSignOnServiceBinding(Saml2MessageBinding.POST)
+        )
+        .build();
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+var relyingPartyRegistration: RelyingPartyRegistration? =
+    RelyingPartyRegistration.withRegistrationId("okta")
+        // ...
+        .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
+            // ...
+            .singleSignOnServiceBinding(Saml2MessageBinding.POST)
+        }
+        .build()
+----
+====
+
+[[servlet-saml2login-sp-initiated-factory-custom-authnrequest]]
+==== Customizing OpenSAML's `AuthnRequest` Instance
+
+There are a number of reasons that you may want to adjust an `AuthnRequest`.
+For example, you may want `ForceAuthN` to be set to `true`, which Spring Security sets to `false` by default.
+
+If you don't need information from the `HttpServletRequest` to make your decision, then the easiest way is to <<servlet-saml2login-opensaml-customization,register a custom `AuthnRequestMarshaller` with OpenSAML>>.
+This will give you access to post-process the `AuthnRequest` instance before it's serialized.
+
+But, if you do need something from the request, then you can use create a custom `Saml2AuthenticationRequestContext` implementation and then a `Converter<Saml2AuthenticationRequestContext, AuthnRequest>` to build an `AuthnRequest` yourself, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+@Component
+public class AuthnRequestConverter implements
+        Converter<MySaml2AuthenticationRequestContext, AuthnRequest> {
+
+    private final AuthnRequestBuilder authnRequestBuilder;
+    private final IssuerBuilder issuerBuilder;
+
+    // ... constructor
+
+    public AuthnRequest convert(Saml2AuthenticationRequestContext context) {
+        MySaml2AuthenticationRequestContext myContext = (MySaml2AuthenticationRequestContext) context;
+        Issuer issuer = issuerBuilder.buildObject();
+        issuer.setValue(myContext.getIssuer());
+
+        AuthnRequest authnRequest = authnRequestBuilder.buildObject();
+        authnRequest.setIssuer(issuer);
+        authnRequest.setDestination(myContext.getDestination());
+        authnRequest.setAssertionConsumerServiceURL(myContext.getAssertionConsumerServiceUrl());
+
+        // ... additional settings
+
+        authRequest.setForceAuthn(myContext.getForceAuthn());
+        return authnRequest;
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Component
+class AuthnRequestConverter : Converter<MySaml2AuthenticationRequestContext, AuthnRequest> {
+    private val authnRequestBuilder: AuthnRequestBuilder? = null
+    private val issuerBuilder: IssuerBuilder? = null
+
+    // ... constructor
+    override fun convert(context: MySaml2AuthenticationRequestContext): AuthnRequest {
+        val myContext: MySaml2AuthenticationRequestContext = context
+        val issuer: Issuer = issuerBuilder.buildObject()
+        issuer.value = myContext.getIssuer()
+        val authnRequest: AuthnRequest = authnRequestBuilder.buildObject()
+        authnRequest.issuer = issuer
+        authnRequest.destination = myContext.getDestination()
+        authnRequest.assertionConsumerServiceURL = myContext.getAssertionConsumerServiceUrl()
+
+        // ... additional settings
+        authRequest.setForceAuthn(myContext.getForceAuthn())
+        return authnRequest
+    }
+}
+----
+====
+
+Then, you can construct your own `Saml2AuthenticationRequestContextResolver` and `Saml2AuthenticationRequestFactory` and publish them as `@Bean` s:
+
+====
+.Java
+[source,java,role="primary"]
+----
+@Bean
+Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver() {
+    Saml2AuthenticationRequestContextResolver resolver =
+            new DefaultSaml2AuthenticationRequestContextResolver();
+    return request -> {
+        Saml2AuthenticationRequestContext context = resolver.resolve(request);
+        return new MySaml2AuthenticationRequestContext(context, request.getParameter("force") != null);
+    };
+}
+
+@Bean
+Saml2AuthenticationRequestFactory authenticationRequestFactory(
+        AuthnRequestConverter authnRequestConverter) {
+
+    OpenSaml4AuthenticationRequestFactory authenticationRequestFactory =
+            new OpenSaml4AuthenticationRequestFactory();
+    authenticationRequestFactory.setAuthenticationRequestContextConverter(authnRequestConverter);
+    return authenticationRequestFactory;
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Bean
+open fun authenticationRequestContextResolver(): Saml2AuthenticationRequestContextResolver {
+    val resolver: Saml2AuthenticationRequestContextResolver = DefaultSaml2AuthenticationRequestContextResolver()
+    return Saml2AuthenticationRequestContextResolver { request: HttpServletRequest ->
+        val context = resolver.resolve(request)
+        MySaml2AuthenticationRequestContext(
+            context,
+            request.getParameter("force") != null
+        )
+    }
+}
+
+@Bean
+open fun authenticationRequestFactory(
+    authnRequestConverter: AuthnRequestConverter?
+): Saml2AuthenticationRequestFactory? {
+    val authenticationRequestFactory = OpenSaml4AuthenticationRequestFactory()
+    authenticationRequestFactory.setAuthenticationRequestContextConverter(authnRequestConverter)
+    return authenticationRequestFactory
+}
+----
+====
+
+[[servlet-saml2login-authenticate-responses]]
+=== Authenticating `<saml2:Response>` s
+
+To verify SAML 2.0 Responses, Spring Security uses <<servlet-saml2login-architecture,`OpenSaml4AuthenticationProvider`>> by default.
+
+You can configure this in a number of ways including:
+
+1. Setting a clock skew to timestamp validation
+2. Mapping the response to a list of `GrantedAuthority` instances
+3. Customizing the strategy for validating assertions
+4. Customizing the strategy for decrypting response and assertion elements
+
+To configure these, you'll use the `saml2Login#authenticationManager` method in the DSL.
+
+[[servlet-saml2login-opensamlauthenticationprovider-clockskew]]
+==== Setting a Clock Skew
+
+It's not uncommon for the asserting and relying parties to have system clocks that aren't perfectly synchronized.
+For that reason, you can configure `OpenSaml4AuthenticationProvider` 's default assertion validator with some tolerance:
+
+====
+.Java
+[source,java,role="primary"]
+----
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();
+        authenticationProvider.setAssertionValidator(OpenSaml4AuthenticationProvider
+                .createDefaultAssertionValidator(assertionToken -> {
+                    Map<String, Object> params = new HashMap<>();
+                    params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis());
+                    // ... other validation parameters
+                    return new ValidationContext(params);
+                })
+        );
+
+        http
+            .authorizeRequests(authz -> authz
+                .anyRequest().authenticated()
+            )
+            .saml2Login(saml2 -> saml2
+                .authenticationManager(new ProviderManager(authenticationProvider))
+            );
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@EnableWebSecurity
+open class SecurityConfig : WebSecurityConfigurerAdapter() {
+    override fun configure(http: HttpSecurity) {
+        val authenticationProvider = OpenSaml4AuthenticationProvider()
+        authenticationProvider.setAssertionValidator(
+            OpenSaml4AuthenticationProvider
+                .createDefaultAssertionValidator(Converter<OpenSaml4AuthenticationProvider.AssertionToken, ValidationContext> {
+                    val params: MutableMap<String, Any> = HashMap()
+                    params[CLOCK_SKEW] =
+                        Duration.ofMinutes(10).toMillis()
+                    ValidationContext(params)
+                })
+        )
+        http {
+            authorizeRequests {
+                authorize(anyRequest, authenticated)
+            }
+            saml2Login {
+                authenticationManager = ProviderManager(authenticationProvider)
+            }
+        }
+    }
+}
+----
+====
+
+[[servlet-saml2login-opensamlauthenticationprovider-userdetailsservice]]
+==== Coordinating with a `UserDetailsService`
+
+Or, perhaps you would like to include user details from a legacy `UserDetailsService`.
+In that case, the response authentication converter can come in handy, as can be seen below:
+
+====
+.Java
+[source,java,role="primary"]
+----
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+    @Autowired
+    UserDetailsService userDetailsService;
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();
+        authenticationProvider.setResponseAuthenticationConverter(responseToken -> {
+            Saml2Authentication authentication = OpenSaml4AuthenticationProvider
+                    .createDefaultResponseAuthenticationConverter() <1>
+                    .convert(responseToken);
+            Assertion assertion = responseToken.getResponse().getAssertions().get(0);
+            String username = assertion.getSubject().getNameID().getValue();
+            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); <2>
+            return MySaml2Authentication(userDetails, authentication); <3>
+        });
+
+        http
+            .authorizeRequests(authz -> authz
+                .anyRequest().authenticated()
+            )
+            .saml2Login(saml2 -> saml2
+                .authenticationManager(new ProviderManager(authenticationProvider))
+            );
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@EnableWebSecurity
+open class SecurityConfig : WebSecurityConfigurerAdapter() {
+    @Autowired
+    var userDetailsService: UserDetailsService? = null
+
+    override fun configure(http: HttpSecurity) {
+        val authenticationProvider = OpenSaml4AuthenticationProvider()
+        authenticationProvider.setResponseAuthenticationConverter { responseToken: OpenSaml4AuthenticationProvider.ResponseToken ->
+            val authentication = OpenSaml4AuthenticationProvider
+                .createDefaultResponseAuthenticationConverter() <1>
+                .convert(responseToken)
+            val assertion: Assertion = responseToken.response.assertions[0]
+            val username: String = assertion.subject.nameID.value
+            val userDetails = userDetailsService!!.loadUserByUsername(username) <2>
+            MySaml2Authentication(userDetails, authentication) <3>
+        }
+        http {
+            authorizeRequests {
+                authorize(anyRequest, authenticated)
+            }
+            saml2Login {
+                authenticationManager = ProviderManager(authenticationProvider)
+            }
+        }
+    }
+}
+----
+====
+<1> First, call the default converter, which extracts attributes and authorities from the response
+<2> Second, call the <<servlet-authentication-userdetailsservice, `UserDetailsService`>> using the relevant information
+<3> Third, return a custom authentication that includes the user details
+
+[NOTE]
+It's not required to call `OpenSaml4AuthenticationProvider` 's default authentication converter.
+It returns a `Saml2AuthenticatedPrincipal` containing the attributes it extracted from `AttributeStatement` s as well as the single `ROLE_USER` authority.
+
+[[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]]
+==== Performing Additional Response Validation
+
+`OpenSaml4AuthenticationProvider` validates the `Issuer` and `Destination` values right after decrypting the `Response`.
+You can customize the validation by extending the default validator concatenating with your own response validator, or you can replace it entirely with yours.
+
+For example, you can throw a custom exception with any additional information available in the `Response` object, like so:
+[source,java]
+----
+OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider();
+provider.setResponseValidator((responseToken) -> {
+	Saml2ResponseValidatorResult result = OpenSamlAuthenticationProvider
+		.createDefaultResponseValidator()
+		.convert(responseToken)
+		.concat(myCustomValidator.convert(responseToken));
+	if (!result.getErrors().isEmpty()) {
+		String inResponseTo = responseToken.getInResponseTo();
+		throw new CustomSaml2AuthenticationException(result, inResponseTo);
+	}
+	return result;
+});
+----
+
+==== Performing Additional Assertion Validation
+`OpenSaml4AuthenticationProvider` performs minimal validation on SAML 2.0 Assertions.
+After verifying the signature, it will:
+
+1. Validate `<AudienceRestriction>` and `<DelegationRestriction>` conditions
+2. Validate `<SubjectConfirmation>` s, expect for any IP address information
+
+To perform additional validation, you can configure your own assertion validator that delegates to `OpenSaml4AuthenticationProvider` 's default and then performs its own.
+
+[[servlet-saml2login-opensamlauthenticationprovider-onetimeuse]]
+For example, you can use OpenSAML's `OneTimeUseConditionValidator` to also validate a `<OneTimeUse>` condition, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider();
+OneTimeUseConditionValidator validator = ...;
+provider.setAssertionValidator(assertionToken -> {
+    Saml2ResponseValidatorResult result = OpenSaml4AuthenticationProvider
+            .createDefaultAssertionValidator()
+            .convert(assertionToken);
+    Assertion assertion = assertionToken.getAssertion();
+    OneTimeUse oneTimeUse = assertion.getConditions().getOneTimeUse();
+    ValidationContext context = new ValidationContext();
+    try {
+        if (validator.validate(oneTimeUse, assertion, context) == ValidationResult.VALID) {
+            return result;
+        }
+    } catch (Exception e) {
+        return result.concat(new Saml2Error(INVALID_ASSERTION, e.getMessage()));
+    }
+    return result.concat(new Saml2Error(INVALID_ASSERTION, context.getValidationFailureMessage()));
+});
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+var provider = OpenSaml4AuthenticationProvider()
+var validator: OneTimeUseConditionValidator = ...
+provider.setAssertionValidator { assertionToken ->
+    val result = OpenSaml4AuthenticationProvider
+        .createDefaultAssertionValidator()
+        .convert(assertionToken)
+    val assertion: Assertion = assertionToken.assertion
+    val oneTimeUse: OneTimeUse = assertion.conditions.oneTimeUse
+    val context = ValidationContext()
+    try {
+        if (validator.validate(oneTimeUse, assertion, context) == ValidationResult.VALID) {
+            return@setAssertionValidator result
+        }
+    } catch (e: Exception) {
+        return@setAssertionValidator result.concat(Saml2Error(INVALID_ASSERTION, e.message))
+    }
+    result.concat(Saml2Error(INVALID_ASSERTION, context.validationFailureMessage))
+}
+----
+====
+
+[NOTE]
+While recommended, it's not necessary to call `OpenSaml4AuthenticationProvider` 's default assertion validator.
+A circumstance where you would skip it would be if you don't need it to check the `<AudienceRestriction>` or the `<SubjectConfirmation>` since you are doing those yourself.
+
+[[servlet-saml2login-opensamlauthenticationprovider-decryption]]
+==== Customizing Decryption
+
+Spring Security decrypts `<saml2:EncryptedAssertion>`, `<saml2:EncryptedAttribute>`, and `<saml2:EncryptedID>` elements automatically by using the decryption <<servlet-saml2login-rpr-credentials,`Saml2X509Credential` instances>> registered in the <<servlet-saml2login-relyingpartyregistration,`RelyingPartyRegistration`>>.
+
+`OpenSaml4AuthenticationProvider` exposes <<servlet-saml2login-architecture,two decryption strategies>>.
+The response decrypter is for decrypting encrypted elements of the `<saml2:Response>`, like `<saml2:EncryptedAssertion>`.
+The assertion decrypter is for decrypting encrypted elements of the `<saml2:Assertion>`, like `<saml2:EncryptedAttribute>` and `<saml2:EncryptedID>`.
+
+You can replace `OpenSaml4AuthenticationProvider`'s default decryption strategy with your own.
+For example, if you have a separate service that decrypts the assertions in a `<saml2:Response>`, you can use it instead like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+MyDecryptionService decryptionService = ...;
+OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider();
+provider.setResponseElementsDecrypter((responseToken) -> decryptionService.decrypt(responseToken.getResponse()));
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val decryptionService: MyDecryptionService = ...
+val provider = OpenSaml4AuthenticationProvider()
+provider.setResponseElementsDecrypter { responseToken -> decryptionService.decrypt(responseToken.response) }
+----
+====
+
+If you are also decrypting individual elements in a `<saml2:Assertion>`, you can customize the assertion decrypter, too:
+
+====
+.Java
+[source,java,role="primary"]
+----
+provider.setAssertionElementsDecrypter((assertionToken) -> decryptionService.decrypt(assertionToken.getAssertion()));
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+provider.setAssertionElementsDecrypter { assertionToken -> decryptionService.decrypt(assertionToken.assertion) }
+----
+====
+
+NOTE: There are two separate decrypters since assertions can be signed separately from responses.
+Trying to decrypt a signed assertion's elements before signature verification may invalidate the signature.
+If your asserting party signs the response only, then it's safe to decrypt all elements using only the response decrypter.
+
+[[servlet-saml2login-authenticationmanager-custom]]
+==== Using a Custom Authentication Manager
+
+[[servlet-saml2login-opensamlauthenticationprovider-authenticationmanager]]
+Of course, the `authenticationManager` DSL method can be also used to perform a completely custom SAML 2.0 authentication.
+This authentication manager should expect a `Saml2AuthenticationToken` object containing the SAML 2.0 Response XML data.
+
+====
+.Java
+[source,java,role="primary"]
+----
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        AuthenticationManager authenticationManager = new MySaml2AuthenticationManager(...);
+        http
+            .authorizeRequests(authorize -> authorize
+                .anyRequest().authenticated()
+            )
+            .saml2Login(saml2 -> saml2
+                .authenticationManager(authenticationManager)
+            )
+        ;
+    }
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@EnableWebSecurity
+open class SecurityConfig : WebSecurityConfigurerAdapter() {
+    override fun configure(http: HttpSecurity) {
+        val customAuthenticationManager: AuthenticationManager = MySaml2AuthenticationManager(...)
+        http {
+            authorizeRequests {
+                authorize(anyRequest, authenticated)
+            }
+            saml2Login {
+                authenticationManager = customAuthenticationManager
+            }
+        }
+    }
+}
+----
+====
+
+[[servlet-saml2login-authenticatedprincipal]]
+=== Using `Saml2AuthenticatedPrincipal`
+
+With the relying party correctly configured for a given asserting party, it's ready to accept assertions.
+Once the relying party validates an assertion, the result is a `Saml2Authentication` with a `Saml2AuthenticatedPrincipal`.
+
+This means that you can access the principal in your controller like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+@Controller
+public class MainController {
+	@GetMapping("/")
+	public String index(@AuthenticationPrincipal Saml2AuthenticatedPrincipal principal, Model model) {
+		String email = principal.getFirstAttribute("email");
+		model.setAttribute("email", email);
+		return "index";
+	}
+}
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+@Controller
+class MainController {
+    @GetMapping("/")
+    fun index(@AuthenticationPrincipal principal: Saml2AuthenticatedPrincipal, model: Model): String {
+        val email = principal.getFirstAttribute<String>("email")
+        model.setAttribute("email", email)
+        return "index"
+    }
+}
+----
+====
+
+[TIP]
+Because the SAML 2.0 specification allows for each attribute to have multiple values, you can either call `getAttribute` to get the list of attributes or `getFirstAttribute` to get the first in the list.
+`getFirstAttribute` is quite handy when you know that there is only one value.
+
+[[servlet-saml2login-metadata]]
+=== Producing `<saml2:SPSSODescriptor>` Metadata
+
+You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below:
+
+====
+.Java
+[source,java,role="primary"]
+----
+Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver =
+        new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);
+Saml2MetadataFilter filter = new Saml2MetadataFilter(
+        relyingPartyRegistrationResolver,
+        new OpenSamlMetadataResolver());
+
+http
+    // ...
+    .saml2Login(withDefaults())
+    .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+val relyingPartyRegistrationResolver: Converter<HttpServletRequest, RelyingPartyRegistration> =
+    DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository)
+val filter = Saml2MetadataFilter(
+    relyingPartyRegistrationResolver,
+    OpenSamlMetadataResolver()
+)
+
+http {
+    //...
+    saml2Login { }
+    addFilterBefore<Saml2WebSsoAuthenticationFilter>(filter)
+}
+----
+====
+
+You can use this metadata endpoint to register your relying party with your asserting party.
+This is often as simple as finding the correct form field to supply the metadata endpoint.
+
+By default, the metadata endpoint is `+/saml2/service-provider-metadata/{registrationId}+`.
+You can change this by calling the `setRequestMatcher` method on the filter:
+
+====
+.Java
+[source,java,role="primary"]
+----
+filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"));
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+filter.setRequestMatcher(AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"))
+----
+====
+
+ensuring that the `registrationId` hint is at the end of the path.
+
+Or, if you have registered a custom relying party registration resolver in the constructor, then you can specify a path without a `registrationId` hint, like so:
+
+====
+.Java
+[source,java,role="primary"]
+----
+filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET"));
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+filter.setRequestMatcher(AntPathRequestMatcher("/saml2/metadata", "GET"))
+----
+====
+
+[[servlet-saml2login-logout]]
+=== Performing Single Logout
+
+Spring Security does not yet support single logout.
+
+Generally speaking, though, you can achieve this by creating and registering a custom `LogoutSuccessHandler` and `RequestMatcher`:
+
+====
+.Java
+[source,java,role="primary"]
+----
+http
+    // ...
+    .logout(logout -> logout
+        .logoutSuccessHandler(myCustomSuccessHandler())
+        .logoutRequestMatcher(myRequestMatcher())
+    )
+----
+
+.Kotlin
+[source,kotlin,role="secondary"]
+----
+http {
+    logout {
+        // ...
+        logoutSuccessHandler = myCustomSuccessHandler()
+        logoutRequestMatcher = myRequestMatcher()
+    }
+}
+----
+====
+
+The success handler will send logout requests to the asserting party.
+
+The request matcher will detect logout requests from the asserting party.
+

+ 7 - 7
docs/modules/ROOT/pages/servlet/test/method.adoc

@@ -1,5 +1,5 @@
 [[test-method]]
-== Testing Method Security
+= Testing Method Security
 
 This section demonstrates how to use Spring Security's Test support to test method based security.
 We first introduce a `MessageService` that requires the user to be authenticated in order to access it.
@@ -41,7 +41,7 @@ Hello org.springframework.security.authentication.UsernamePasswordAuthentication
 ----
 
 [[test-method-setup]]
-=== Security Test Setup
+== Security Test Setup
 
 Before we can use Spring Security Test support, we must perform some setup. An example can be seen below:
 
@@ -98,7 +98,7 @@ fun getMessageUnauthenticated() {
 ====
 
 [[test-method-withmockuser]]
-=== @WithMockUser
+== @WithMockUser
 
 The question is "How could we most easily run the test as a specific user?"
 The answer is to use `@WithMockUser`.
@@ -294,7 +294,7 @@ You can change this to happen during the `TestExecutionListener.beforeTestExecut
 
 
 [[test-method-withanonymoususer]]
-=== @WithAnonymousUser
+== @WithAnonymousUser
 
 Using `@WithAnonymousUser` allows running as an anonymous user.
 This is especially convenient when you wish to run most of your tests with a specific user, but want to run a few tests as an anonymous user.
@@ -358,7 +358,7 @@ You can change this to happen during the `TestExecutionListener.beforeTestExecut
 
 
 [[test-method-withuserdetails]]
-=== @WithUserDetails
+== @WithUserDetails
 
 While `@WithMockUser` is a very convenient way to get started, it may not work in all instances.
 For example, it is common for applications to expect that the `Authentication` principal be of a specific type.
@@ -462,7 +462,7 @@ You can change this to happen during the `TestExecutionListener.beforeTestExecut
 
 
 [[test-method-withsecuritycontext]]
-=== @WithSecurityContext
+== @WithSecurityContext
 
 We have seen that `@WithMockUser` is an excellent choice if we are not using a custom `Authentication` principal.
 Next we discovered that `@WithUserDetails` would allow us to use a custom `UserDetailsService` to create our `Authentication` principal but required the user to exist.
@@ -596,7 +596,7 @@ You can change this to happen during the `TestExecutionListener.beforeTestExecut
 
 
 [[test-method-meta-annotations]]
-=== Test Meta Annotations
+== Test Meta Annotations
 
 If you reuse the same user within your tests often, it is not ideal to have to repeatedly specify the attributes.
 For example, if there are many tests related to an administrative user with the username "admin" and the roles `ROLE_USER` and `ROLE_ADMIN` you would have to write:

+ 33 - 33
docs/modules/ROOT/pages/servlet/test/mockmvc.adoc

@@ -1,10 +1,10 @@
 [[test-mockmvc]]
-== Spring MVC Test Integration
+= Spring MVC Test Integration
 
 Spring Security provides comprehensive integration with https://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#spring-mvc-test-framework[Spring MVC Test]
 
 [[test-mockmvc-setup]]
-=== Setting Up MockMvc and Spring Security
+== Setting Up MockMvc and Spring Security
 
 In order to use Spring Security with Spring MVC Test it is necessary to add the Spring Security `FilterChainProxy` as a `Filter`.
 It is also necessary to add Spring Security's `TestSecurityContextHolderPostProcessor` to support <<Running as a User in Spring MVC Test with Annotations,Running as a User in Spring MVC Test with Annotations>>.
@@ -68,7 +68,7 @@ class CsrfShowcaseTests {
 <1> `SecurityMockMvcConfigurers.springSecurity()` will perform all of the initial setup we need to integrate Spring Security with Spring MVC Test
 
 [[test-mockmvc-smmrpp]]
-=== SecurityMockMvcRequestPostProcessors
+== SecurityMockMvcRequestPostProcessors
 
 Spring MVC Test provides a convenient interface called a `RequestPostProcessor` that can be used to modify a request.
 Spring Security provides a number of `RequestPostProcessor` implementations that make testing easier.
@@ -89,7 +89,7 @@ import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequ
 ====
 
 [[test-mockmvc-csrf]]
-==== Testing with CSRF Protection
+=== Testing with CSRF Protection
 
 When testing any non-safe HTTP methods and using Spring Security's CSRF protection, you must be sure to include a valid CSRF Token in the request.
 To specify a valid CSRF token as a request parameter using the following:
@@ -150,7 +150,7 @@ mvc.post("/") {
 ====
 
 [[test-mockmvc-securitycontextholder]]
-==== Running a Test as a User in Spring MVC Test
+=== Running a Test as a User in Spring MVC Test
 
 It is often desirable to run tests as a specific user.
 There are two simple ways of populating the user:
@@ -159,7 +159,7 @@ There are two simple ways of populating the user:
 * <<Running as a User in Spring MVC Test with Annotations,Running as a User in Spring MVC Test with Annotations>>
 
 [[test-mockmvc-securitycontextholder-rpp]]
-==== Running as a User in Spring MVC Test with RequestPostProcessor
+=== Running as a User in Spring MVC Test with RequestPostProcessor
 
 There are a number of options available to associate a user to the current `HttpServletRequest`.
 For example, the following will run as a user (which does not need to exist) with the username "user", the password "password", and the role "ROLE_USER":
@@ -364,7 +364,7 @@ mvc.get("/") {
 ----
 ====
 
-===== Running as a User in Spring MVC Test with Annotations
+==== Running as a User in Spring MVC Test with Annotations
 
 As an alternative to using a `RequestPostProcessor` to create your user, you can use annotations described in <<Testing Method Security>>.
 For example, the following will run the test with the user with username "user", password "password", and role "ROLE_USER":
@@ -423,7 +423,7 @@ fun requestProtectedUrlWithUser() {
 ----
 ====
 
-==== Testing HTTP Basic Authentication
+=== Testing HTTP Basic Authentication
 
 While it has always been possible to authenticate with HTTP Basic, it was a bit tedious to remember the header name, format, and encode the values.
 Now this can be done using Spring Security's `httpBasic` `RequestPostProcessor`.
@@ -454,7 +454,7 @@ Authorization: Basic dXNlcjpwYXNzd29yZA==
 ----
 
 [[testing-oauth2]]
-==== Testing OAuth 2.0
+=== Testing OAuth 2.0
 
 When it comes to OAuth 2.0, the same principles covered earlier still apply: Ultimately, it depends on what your method under test is expecting to be in the `SecurityContextHolder`.
 
@@ -507,7 +507,7 @@ fun foo(@AuthenticationPrincipal user: OidcUser): String {
 then Spring Security's test support can come in handy.
 
 [[testing-oidc-login]]
-==== Testing OIDC Login
+=== Testing OIDC Login
 
 Testing the method above with Spring MVC Test would require simulating some kind of grant flow with an authorization server.
 Certainly this would be a daunting task, which is why Spring Security ships with support for removing this boilerplate.
@@ -589,7 +589,7 @@ Further, it also links that `OidcUser` to a simple instance of `OAuth2Authorized
 This can be handy if your tests <<testing-oauth2-client,use the `@RegisteredOAuth2AuthorizedClient` annotation>>..
 
 [[testing-oidc-login-authorities]]
-===== Configuring Authorities
+==== Configuring Authorities
 
 In many circumstances, your method is protected by filter or method security and needs your `Authentication` to have certain granted authorities to allow the request.
 
@@ -619,7 +619,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-oidc-login-claims]]
-===== Configuring Claims
+==== Configuring Claims
 
 And while granted authorities are quite common across all of Spring Security, we also have claims in the case of OAuth 2.0.
 
@@ -678,7 +678,7 @@ mvc.get("/endpoint") {
 since `OidcUser` collects its claims from `OidcIdToken`.
 
 [[testing-oidc-login-user]]
-===== Additional Configurations
+==== Additional Configurations
 
 There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects:
 
@@ -724,7 +724,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-oauth2-login]]
-==== Testing OAuth 2.0 Login
+=== Testing OAuth 2.0 Login
 
 As with <<testing-oidc-login,testing OIDC login>>, testing OAuth 2.0 Login presents a similar challenge of mocking a grant flow.
 And because of that, Spring Security also has test support for non-OIDC use cases.
@@ -812,7 +812,7 @@ Further, it also links that `OAuth2User` to a simple instance of `OAuth2Authoriz
 This can be handy if your tests <<testing-oauth2-client,use the `@RegisteredOAuth2AuthorizedClient` annotation>>.
 
 [[testing-oauth2-login-authorities]]
-===== Configuring Authorities
+==== Configuring Authorities
 
 In many circumstances, your method is protected by filter or method security and needs your `Authentication` to have certain granted authorities to allow the request.
 
@@ -842,7 +842,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-oauth2-login-claims]]
-===== Configuring Claims
+==== Configuring Claims
 
 And while granted authorities are quite common across all of Spring Security, we also have claims in the case of OAuth 2.0.
 
@@ -897,7 +897,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-oauth2-login-user]]
-===== Additional Configurations
+==== Additional Configurations
 
 There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects:
 
@@ -942,7 +942,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-oauth2-client]]
-==== Testing OAuth 2.0 Clients
+=== Testing OAuth 2.0 Clients
 
 Independent of how your user authenticates, you may have other tokens and client registrations that are in play for the request you are testing.
 For example, your controller may be relying on the client credentials grant to get a token that isn't associated with the user at all:
@@ -1054,7 +1054,7 @@ assertThat(authorizedClient.accessToken.scopes).containsExactly("read")
 The client can then be retrieved as normal using `@RegisteredOAuth2AuthorizedClient` in a controller method.
 
 [[testing-oauth2-client-scopes]]
-===== Configuring Scopes
+==== Configuring Scopes
 
 In many circumstances, the OAuth 2.0 access token comes with a set of scopes.
 If your controller inspects these, say like so:
@@ -1121,7 +1121,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-oauth2-client-registration]]
-===== Additional Configurations
+==== Additional Configurations
 
 There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects:
 
@@ -1167,7 +1167,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-jwt]]
-==== Testing JWT Authentication
+=== Testing JWT Authentication
 
 In order to make an authorized request on a resource server, you need a bearer token.
 
@@ -1177,7 +1177,7 @@ All of this can be quite daunting, especially when this isn't the focus of your
 Fortunately, there are a number of simple ways that you can overcome this difficulty and allow your tests to focus on authorization and not on representing bearer tokens.
 We'll look at two of them now:
 
-===== `jwt() RequestPostProcessor`
+==== `jwt() RequestPostProcessor`
 
 The first way is via a `RequestPostProcessor`.
 The simplest of these would look something like this:
@@ -1357,7 +1357,7 @@ mvc.get("/endpoint") {
 ----
 ====
 
-===== `authentication()` `RequestPostProcessor`
+==== `authentication()` `RequestPostProcessor`
 
 The second way is by using the `authentication()` `RequestPostProcessor`.
 Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test, like so:
@@ -1399,7 +1399,7 @@ mvc.get("/endpoint") {
 Note that as an alternative to these, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation.
 
 [[testing-opaque-token]]
-==== Testing Opaque Token Authentication
+=== Testing Opaque Token Authentication
 
 Similar to <<testing-jwt,JWTs>>, opaque tokens require an authorization server in order to verify their validity, which can make testing more difficult.
 To help with that, Spring Security has test support for opaque tokens.
@@ -1484,7 +1484,7 @@ assertThat(token.authorities).containsExactly(SimpleGrantedAuthority("SCOPE_read
 Spring Security does the necessary work to make sure that the `BearerTokenAuthentication` instance is available for your controller methods.
 
 [[testing-opaque-token-authorities]]
-===== Configuring Authorities
+==== Configuring Authorities
 
 In many circumstances, your method is protected by filter or method security and needs your `Authentication` to have certain granted authorities to allow the request.
 
@@ -1514,7 +1514,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-opaque-token-attributes]]
-===== Configuring Claims
+==== Configuring Claims
 
 And while granted authorities are quite common across all of Spring Security, we also have attributes in the case of OAuth 2.0.
 
@@ -1569,7 +1569,7 @@ mvc.get("/endpoint") {
 ====
 
 [[testing-opaque-token-principal]]
-===== Additional Configurations
+==== Additional Configurations
 
 There are additional methods, too, for further configuring the authentication; it simply depends on what data your controller expects.
 
@@ -1616,7 +1616,7 @@ mvc.get("/endpoint") {
 
 Note that as an alternative to using `opaqueToken()` test support, you can also mock the `OpaqueTokenIntrospector` bean itself with a `@MockBean` annotation.
 
-=== SecurityMockMvcRequestBuilders
+== SecurityMockMvcRequestBuilders
 
 Spring MVC Test also provides a `RequestBuilder` interface that can be used to create the `MockHttpServletRequest` used in your test.
 Spring Security provides a few `RequestBuilder` implementations that can be used to make testing easier.
@@ -1636,7 +1636,7 @@ import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequ
 ----
 ====
 
-==== Testing Form Based Authentication
+=== Testing Form Based Authentication
 
 You can easily create a request to test a form based authentication using Spring Security's testing support.
 For example, the following will submit a POST to "/login" with the username "user", the password "password", and a valid CSRF token:
@@ -1696,7 +1696,7 @@ mvc
 ====
 
 [[test-logout]]
-==== Testing Logout
+=== Testing Logout
 
 While fairly trivial using standard Spring MVC Test, you can use Spring Security's testing support to make testing log out easier.
 For example, the following will submit a POST to "/logout" with a valid CSRF token:
@@ -1736,7 +1736,7 @@ mvc
 ----
 ====
 
-=== SecurityMockMvcResultMatchers
+== SecurityMockMvcResultMatchers
 
 At times it is desirable to make various security related assertions about a request.
 To accommodate this need, Spring Security Test support implements Spring MVC Test's `ResultMatcher` interface.
@@ -1757,7 +1757,7 @@ import org.springframework.security.test.web.servlet.response.SecurityMockMvcRes
 ----
 ====
 
-==== Unauthenticated Assertion
+=== Unauthenticated Assertion
 
 At times it may be valuable to assert that there is no authenticated user associated with the result of a `MockMvc` invocation.
 For example, you might want to test submitting an invalid username and password and verify that no user is authenticated.
@@ -1781,7 +1781,7 @@ mvc
 ----
 ====
 
-==== Authenticated Assertion
+=== Authenticated Assertion
 
 It is often times that we must assert that an authenticated user exists.
 For example, we may want to verify that we authenticated successfully.

Some files were not shown because too many files changed in this diff